Skip to content

Commit 971f4cd

Browse files
committed
Add new package: server
This package is used to orchestrate everything. It prints the initial start text, creates the channels used between the incoming protocol and renderers, and starts the goroutines. Server has one protocol, which we use for incoming requests. At this point it's only http. Sever can have many renderers, which we use to output the incoming requests from the protocol. At this point we have two, printing to the terminal, or writing to a log file.
1 parent 4a839f2 commit 971f4cd

File tree

2 files changed

+183
-0
lines changed

2 files changed

+183
-0
lines changed

pkg/server/server.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package server
2+
3+
import (
4+
"fmt"
5+
"sync"
6+
7+
"github.com/aaronvb/request_hole/pkg/protocol"
8+
"github.com/aaronvb/request_hole/pkg/renderer"
9+
"github.com/pterm/pterm"
10+
)
11+
12+
// Server orchestrates the start and channels for the protocol and renderers.
13+
type Server struct {
14+
// FlagData contains the data from the CLI flags.
15+
FlagData
16+
17+
// Protocol which we receive incoming requests to. The protocol uses a channel
18+
// to send incoming requests to the renderers.
19+
Protocol protocol.Protocol
20+
21+
// Renderers contains a slice of renderer's. Each will run within it's own
22+
// goroutine.
23+
Renderers []renderer.Renderer
24+
}
25+
26+
// FlagData contains the data from the CLI flags.
27+
type FlagData struct {
28+
// Addr is the address the HTTP server will bind to.
29+
Addr string
30+
31+
// BuildInfo contains the build information for rh. Set by goreleaser.
32+
BuildInfo map[string]string
33+
34+
// Details determines if header details should be shown with the request,
35+
Details bool
36+
37+
// LogFile contains the path and filename to the log file which the server
38+
// will write to if log flag is passed.
39+
LogFile string
40+
41+
// Port is the port the HTTP server will run on.
42+
Port int
43+
44+
// ResponseCode is the response which our endpoint will return.
45+
// Default is 200 if no response code is passed.
46+
ResponseCode int
47+
48+
}
49+
50+
// Start handles all of the orchestration.
51+
//
52+
// Prints the CLI header which we use to show flags passed to the CLI(ie: port).
53+
//
54+
// Creates a waitgroup for each goroutine.
55+
//
56+
// Creates a channel between the protocol and renderers to handle incoming request
57+
// payloads and exiting due to errors.
58+
//
59+
// Blocks main program until all goroutines are returned. In most cases the user will
60+
// force exit the CLI from the terminal.
61+
func (s *Server) Start() {
62+
s.printServerInfo()
63+
64+
if len(s.Renderers) == 0 {
65+
pterm.Error.WithShowLineNumber(true).Println("No render provided")
66+
return
67+
}
68+
69+
var wg sync.WaitGroup
70+
var rpChans []chan protocol.RequestPayload
71+
var quitChans []chan int
72+
73+
for _, renderer := range s.Renderers {
74+
rp := make(chan protocol.RequestPayload)
75+
q := make(chan int)
76+
77+
wg.Add(1)
78+
go renderer.Start(&wg, rp, q)
79+
80+
rpChans = append(rpChans, rp)
81+
quitChans = append(quitChans, q)
82+
}
83+
84+
wg.Add(1)
85+
go s.Protocol.Start(&wg, rpChans, quitChans)
86+
87+
wg.Wait()
88+
}
89+
90+
// printServerInfo prints the top header section of the CLI when we start.
91+
// This contains info such as flag options passed and build info.
92+
func (s *Server) printServerInfo() {
93+
clear()
94+
95+
text := s.startText()
96+
97+
pterm.DefaultBox.
98+
WithBoxStyle(pterm.NewStyle(pterm.FgGray)).
99+
Printfln(text)
100+
}
101+
102+
func (s *Server) startText() string {
103+
primary := pterm.DefaultBasicText.
104+
WithStyle(pterm.NewStyle(pterm.Bold)).
105+
Sprintf("Request Hole")
106+
version := pterm.DefaultBasicText.
107+
WithStyle(pterm.NewStyle(pterm.Fuzzy)).
108+
Sprintf(s.FlagData.BuildInfo["version"])
109+
110+
text := fmt.Sprintf("%s %s\nListening on http://%s:%d", primary, version, s.FlagData.Addr, s.FlagData.Port)
111+
112+
if s.FlagData.Details {
113+
text = fmt.Sprintf("%s\nDetails: %t", text, s.FlagData.Details)
114+
}
115+
116+
if s.FlagData.LogFile != "" {
117+
text = fmt.Sprintf("%s\nLog: %s", text, s.FlagData.LogFile)
118+
}
119+
120+
return text
121+
}
122+
123+
// clear will clear the terminal, called at the start.
124+
func clear() {
125+
print("\033[H\033[2J")
126+
}

pkg/server/server_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package server
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/pterm/pterm"
8+
)
9+
10+
func TestStartText(t *testing.T) {
11+
pterm.DisableColor()
12+
flags := FlagData{Addr: "localhost", Port: 8080, BuildInfo: map[string]string{"version": "dev"}}
13+
server := Server{FlagData: flags}
14+
result := server.startText()
15+
expected := fmt.Sprintf("Request Hole %s\nListening on http://%s:%d", "dev", server.FlagData.Addr, server.FlagData.Port)
16+
17+
if result != expected {
18+
t.Errorf("Expected %s, got %s", expected, result)
19+
}
20+
}
21+
22+
func TestStartTextWithDetails(t *testing.T) {
23+
pterm.DisableColor()
24+
flags := FlagData{
25+
Addr: "localhost",
26+
Port: 8080,
27+
BuildInfo: map[string]string{"version": "dev"},
28+
Details: true}
29+
server := Server{FlagData: flags}
30+
result := server.startText()
31+
expected := fmt.Sprintf(
32+
"Request Hole %s\nListening on http://%s:%d\nDetails: %t", "dev",
33+
server.FlagData.Addr, server.FlagData.Port, server.FlagData.Details)
34+
35+
if result != expected {
36+
t.Errorf("Expected %s, got %s", expected, result)
37+
}
38+
}
39+
40+
func TestStartTextWithLogFile(t *testing.T) {
41+
pterm.DisableColor()
42+
flags := FlagData{
43+
Addr: "localhost",
44+
Port: 8080,
45+
BuildInfo: map[string]string{"version": "dev"},
46+
LogFile: "rh.log",
47+
}
48+
server := Server{FlagData: flags}
49+
result := server.startText()
50+
expected := fmt.Sprintf(
51+
"Request Hole %s\nListening on http://%s:%d\nLog: %s", "dev",
52+
server.FlagData.Addr, server.FlagData.Port, server.FlagData.LogFile)
53+
54+
if result != expected {
55+
t.Errorf("Expected %s, got %s", expected, result)
56+
}
57+
}

0 commit comments

Comments
 (0)