Skip to content

Commit ad8c75c

Browse files
authored
Merge pull request #14 from gatewayd-io/add-cli
Add CLI application skeleton
2 parents 82b88f9 + f873a67 commit ad8c75c

File tree

5 files changed

+172
-122
lines changed

5 files changed

+172
-122
lines changed

cmd/root.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package cmd
2+
3+
import (
4+
"os"
5+
6+
"github.com/spf13/cobra"
7+
)
8+
9+
var rootCmd = &cobra.Command{
10+
Use: "gatewayd",
11+
Short: "A cloud-native database gateway and framework for building data-driven applications",
12+
Long: "GatewayD is a cloud-native database gateway and framework for building data-driven " +
13+
"applications. It sits in between your database(s) and your database client(s) and " +
14+
"proxies all queries to and their responses from the database.",
15+
}
16+
17+
func Execute() {
18+
if err := rootCmd.Execute(); err != nil {
19+
os.Exit(1)
20+
}
21+
}
22+
23+
func init() {}

cmd/run.go

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package cmd
2+
3+
import (
4+
"os"
5+
"os/signal"
6+
"syscall"
7+
"time"
8+
9+
"github.com/gatewayd-io/gatewayd/logging"
10+
"github.com/gatewayd-io/gatewayd/network"
11+
"github.com/panjf2000/gnet/v2"
12+
"github.com/rs/zerolog"
13+
"github.com/spf13/cobra"
14+
)
15+
16+
const (
17+
DefaultTCPKeepAlive = 3 * time.Second
18+
)
19+
20+
// runCmd represents the run command.
21+
var runCmd = &cobra.Command{
22+
Use: "run",
23+
Short: "Run a gatewayd instance",
24+
Run: func(cmd *cobra.Command, args []string) {
25+
// Create a logger
26+
logger := logging.NewLogger(nil, zerolog.TimeFormatUnix, zerolog.InfoLevel, true)
27+
28+
// Create a pool
29+
pool := network.NewPool(logger)
30+
31+
// Add a client to the pool
32+
for i := 0; i < network.DefaultPoolSize; i++ {
33+
client := network.NewClient("tcp", "localhost:5432", network.DefaultBufferSize, logger)
34+
if client != nil {
35+
if err := pool.Put(client); err != nil {
36+
logger.Panic().Err(err).Msg("Failed to add client to pool")
37+
}
38+
}
39+
}
40+
41+
// Verify that the pool is properly populated
42+
logger.Debug().Msgf("There are %d clients in the pool", len(pool.ClientIDs()))
43+
if len(pool.ClientIDs()) != network.DefaultPoolSize {
44+
logger.Error().Msg(
45+
"The pool size is incorrect, either because " +
46+
"the clients are cannot connect (no network connectivity) " +
47+
"or the server is not running. Exiting...")
48+
os.Exit(1)
49+
}
50+
51+
// Create a prefork proxy with the pool of clients
52+
proxy := network.NewProxy(pool, false, false, &network.Client{
53+
Network: "tcp",
54+
Address: "localhost:5432",
55+
ReceiveBufferSize: network.DefaultBufferSize,
56+
}, logger)
57+
58+
// Create a server
59+
server := network.NewServer(
60+
"tcp",
61+
"0.0.0.0:15432",
62+
0,
63+
0,
64+
network.DefaultTickInterval,
65+
[]gnet.Option{
66+
// Scheduling options
67+
gnet.WithMulticore(true),
68+
gnet.WithLockOSThread(false),
69+
// NumEventLoop overrides Multicore option.
70+
// gnet.WithNumEventLoop(1),
71+
72+
// Can be used to send keepalive messages to the client.
73+
gnet.WithTicker(false),
74+
75+
// Internal event-loop load balancing options
76+
gnet.WithLoadBalancing(gnet.RoundRobin),
77+
78+
// Logger options
79+
// TODO: This is a temporary solution and will be replaced.
80+
// gnet.WithLogger(logrus.New()),
81+
// gnet.WithLogPath("./gnet.log"),
82+
// gnet.WithLogLevel(zapcore.DebugLevel),
83+
84+
// Buffer options
85+
// TODO: This should be configurable and optimized.
86+
gnet.WithReadBufferCap(network.DefaultBufferSize),
87+
gnet.WithWriteBufferCap(network.DefaultBufferSize),
88+
gnet.WithSocketRecvBuffer(network.DefaultBufferSize),
89+
gnet.WithSocketSendBuffer(network.DefaultBufferSize),
90+
91+
// TCP options
92+
gnet.WithReuseAddr(true),
93+
gnet.WithReusePort(true),
94+
gnet.WithTCPKeepAlive(DefaultTCPKeepAlive),
95+
gnet.WithTCPNoDelay(gnet.TCPNoDelay),
96+
},
97+
nil,
98+
nil,
99+
proxy,
100+
logger,
101+
)
102+
103+
// Shutdown the server gracefully
104+
var signals []os.Signal
105+
signals = append(signals,
106+
os.Interrupt,
107+
os.Kill,
108+
syscall.SIGTERM,
109+
syscall.SIGABRT,
110+
syscall.SIGQUIT,
111+
syscall.SIGHUP,
112+
syscall.SIGINT,
113+
)
114+
signalsCh := make(chan os.Signal, 1)
115+
signal.Notify(signalsCh, signals...)
116+
go func() {
117+
for sig := range signalsCh {
118+
for _, s := range signals {
119+
if sig != s {
120+
server.Shutdown()
121+
os.Exit(0)
122+
}
123+
}
124+
}
125+
}()
126+
127+
// Run the server
128+
if err := server.Run(); err != nil {
129+
logger.Error().Err(err).Msg("Failed to start server")
130+
}
131+
},
132+
}
133+
134+
func init() {
135+
rootCmd.AddCommand(runCmd)
136+
}

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@ require (
66
github.com/fergusstrange/embedded-postgres v1.19.0
77
github.com/panjf2000/gnet/v2 v2.1.2
88
github.com/rs/zerolog v1.28.0
9+
github.com/spf13/cobra v1.6.1
910
github.com/stretchr/testify v1.8.1
1011
)
1112

1213
require (
1314
github.com/davecgh/go-spew v1.1.1 // indirect
15+
github.com/inconshreveable/mousetrap v1.0.1 // indirect
1416
github.com/lib/pq v1.10.7 // indirect
1517
github.com/mattn/go-colorable v0.1.13 // indirect
1618
github.com/mattn/go-isatty v0.0.16 // indirect
1719
github.com/pmezard/go-difflib v1.0.0 // indirect
20+
github.com/spf13/pflag v1.0.5 // indirect
1821
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
1922
go.uber.org/atomic v1.10.0 // indirect
2023
go.uber.org/multierr v1.8.0 // indirect

go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
33
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
44
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
55
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
6+
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
67
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
78
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
89
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
910
github.com/fergusstrange/embedded-postgres v1.19.0 h1:NqDufJHeA03U7biULlPHZ0pZ10/mDOMKPILEpT50Fyk=
1011
github.com/fergusstrange/embedded-postgres v1.19.0/go.mod h1:0B+3bPsMvcNgR9nN+bdM2x9YaNYDnf3ksUqYp1OAub0=
1112
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
13+
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
14+
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
1215
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
1316
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
1417
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -35,6 +38,11 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
3538
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
3639
github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY=
3740
github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
41+
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
42+
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
43+
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
44+
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
45+
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
3846
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
3947
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
4048
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=

main.go

Lines changed: 2 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,7 @@
11
package main
22

3-
import (
4-
"os"
5-
"os/signal"
6-
"syscall"
7-
"time"
3+
import "github.com/gatewayd-io/gatewayd/cmd"
84

9-
"github.com/gatewayd-io/gatewayd/logging"
10-
"github.com/gatewayd-io/gatewayd/network"
11-
"github.com/panjf2000/gnet/v2"
12-
"github.com/rs/zerolog"
13-
)
14-
15-
const (
16-
DefaultTCPKeepAlive = 3 * time.Second
17-
)
18-
19-
//nolint:funlen
205
func main() {
21-
// Create a logger
22-
logger := logging.NewLogger(nil, zerolog.TimeFormatUnix, zerolog.InfoLevel, true)
23-
24-
// Create a pool
25-
pool := network.NewPool(logger)
26-
27-
// Add a client to the pool
28-
for i := 0; i < network.DefaultPoolSize; i++ {
29-
client := network.NewClient("tcp", "localhost:5432", network.DefaultBufferSize, logger)
30-
if client != nil {
31-
if err := pool.Put(client); err != nil {
32-
logger.Panic().Err(err).Msg("Failed to add client to pool")
33-
}
34-
}
35-
}
36-
37-
// Verify that the pool is properly populated
38-
logger.Debug().Msgf("There are %d clients in the pool", len(pool.ClientIDs()))
39-
if len(pool.ClientIDs()) != network.DefaultPoolSize {
40-
logger.Error().Msg(
41-
"The pool size is incorrect, either because " +
42-
"the clients are cannot connect (no network connectivity) " +
43-
"or the server is not running. Exiting...")
44-
os.Exit(1)
45-
}
46-
47-
// Create a prefork proxy with the pool of clients
48-
proxy := network.NewProxy(pool, false, false, &network.Client{
49-
Network: "tcp",
50-
Address: "localhost:5432",
51-
ReceiveBufferSize: network.DefaultBufferSize,
52-
}, logger)
53-
54-
// Create a server
55-
server := network.NewServer(
56-
"tcp",
57-
"0.0.0.0:15432",
58-
0,
59-
0,
60-
network.DefaultTickInterval,
61-
[]gnet.Option{
62-
// Scheduling options
63-
gnet.WithMulticore(true),
64-
gnet.WithLockOSThread(false),
65-
// NumEventLoop overrides Multicore option.
66-
// gnet.WithNumEventLoop(1),
67-
68-
// Can be used to send keepalive messages to the client.
69-
gnet.WithTicker(false),
70-
71-
// Internal event-loop load balancing options
72-
gnet.WithLoadBalancing(gnet.RoundRobin),
73-
74-
// Logger options
75-
// TODO: This is a temporary solution and will be replaced.
76-
// gnet.WithLogger(logrus.New()),
77-
// gnet.WithLogPath("./gnet.log"),
78-
// gnet.WithLogLevel(zapcore.DebugLevel),
79-
80-
// Buffer options
81-
// TODO: This should be configurable and optimized.
82-
gnet.WithReadBufferCap(network.DefaultBufferSize),
83-
gnet.WithWriteBufferCap(network.DefaultBufferSize),
84-
gnet.WithSocketRecvBuffer(network.DefaultBufferSize),
85-
gnet.WithSocketSendBuffer(network.DefaultBufferSize),
86-
87-
// TCP options
88-
gnet.WithReuseAddr(true),
89-
gnet.WithReusePort(true),
90-
gnet.WithTCPKeepAlive(DefaultTCPKeepAlive),
91-
gnet.WithTCPNoDelay(gnet.TCPNoDelay),
92-
},
93-
nil,
94-
nil,
95-
proxy,
96-
logger,
97-
)
98-
99-
// Shutdown the server gracefully
100-
var signals []os.Signal
101-
signals = append(signals,
102-
os.Interrupt,
103-
os.Kill,
104-
syscall.SIGTERM,
105-
syscall.SIGABRT,
106-
syscall.SIGQUIT,
107-
syscall.SIGHUP,
108-
syscall.SIGINT,
109-
)
110-
signalsCh := make(chan os.Signal, 1)
111-
signal.Notify(signalsCh, signals...)
112-
go func() {
113-
for sig := range signalsCh {
114-
for _, s := range signals {
115-
if sig != s {
116-
server.Shutdown()
117-
os.Exit(0)
118-
}
119-
}
120-
}
121-
}()
122-
123-
// Run the server
124-
if err := server.Run(); err != nil {
125-
logger.Error().Err(err).Msg("Failed to start server")
126-
}
6+
cmd.Execute()
1277
}

0 commit comments

Comments
 (0)