Skip to content

Commit d53ddda

Browse files
committed
Implement Go server template
1 parent 1f4ce2c commit d53ddda

File tree

9 files changed

+292
-24
lines changed

9 files changed

+292
-24
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ codegame --help
2727
- Create a new client
2828
- Go
2929
- Create a new game server
30-
- not implemented
30+
- Go
3131

3232
## Installation
3333

commands/new.go

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,25 @@ func New() error {
5858
}
5959

6060
func newServer(projectName string) error {
61-
return cli.Error("Not implemented.")
61+
var language string
62+
if pflag.NArg() >= 3 {
63+
language = strings.ToLower(pflag.Arg(2))
64+
} else {
65+
var err error
66+
language, err = cli.Select("In which language do you want to write your project?", []string{"Go"}, []string{"go"})
67+
if err != nil {
68+
return err
69+
}
70+
}
71+
72+
var err error
73+
switch language {
74+
case "go":
75+
err = newGoServer(projectName)
76+
default:
77+
return cli.Error("Unsupported language: %s", language)
78+
}
79+
return err
6280
}
6381

6482
func newClient(projectName string) error {
@@ -109,15 +127,11 @@ func newClient(projectName string) error {
109127

110128
switch language {
111129
case "go":
112-
err = newClientGo(projectName, url, cgVersion)
130+
err = newGoClient(projectName, url, cgVersion)
113131
default:
114132
return cli.Error("Unsupported language: %s", language)
115133
}
116-
if err != nil {
117-
return err
118-
}
119-
120-
return nil
134+
return err
121135
}
122136

123137
func getCodeGameInfo(baseURL string) (string, string, error) {

commands/new_go.go

Lines changed: 179 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,38 +13,55 @@ import (
1313
"github.com/code-game-project/codegame-cli/external"
1414
)
1515

16-
//go:embed templates/main.go.tmpl
17-
var goMainTemplate string
16+
//go:embed templates/go/client/main.go.tmpl
17+
var goClientMainTemplate string
1818

19-
func newClientGo(projectName, serverURL, cgVersion string) error {
20-
err := createGoTemplate(projectName, serverURL)
19+
//go:embed templates/go/server/main.go.tmpl
20+
var goServerMainTemplate string
21+
22+
//go:embed templates/go/server/game.go.tmpl
23+
var goServerGameTemplate string
24+
25+
//go:embed templates/go/server/events.cge.tmpl
26+
var goServerCGETemplate string
27+
28+
//go:embed templates/go/server/events.go.tmpl
29+
var goServerEventsTemplate string
30+
31+
func newGoClient(projectName, serverURL, cgVersion string) error {
32+
err := createGoClientTemplate(projectName, serverURL)
2133
if err != nil {
2234
return err
2335
}
2436

25-
err = installGoLibrary(projectName, cgVersion)
37+
err = installGoClientLibrary(projectName, cgVersion)
2638
if err != nil {
2739
return err
2840
}
2941

3042
cli.Begin("Cleaning up...")
31-
err = external.ExecuteInDir(projectName, "go", "mod", "tidy")
32-
if err != nil {
33-
return err
34-
}
3543

3644
if !external.IsInstalled("goimports") {
3745
cli.Warn("Failed to add import statements: 'goimports' is not installed!")
3846
return nil
3947
}
4048

4149
external.ExecuteInDir(projectName, "goimports", "-w", "main.go")
50+
51+
out, err := external.ExecuteInDirHidden(projectName, "go", "mod", "tidy")
52+
if err != nil {
53+
if out != "" {
54+
cli.Error(out)
55+
}
56+
return err
57+
}
58+
4259
cli.Finish()
4360

4461
return nil
4562
}
4663

47-
func createGoTemplate(projectName, serverURL string) error {
64+
func createGoClientTemplate(projectName, serverURL string) error {
4865
module, err := cli.Input("Project module path:")
4966
if err != nil {
5067
return err
@@ -59,7 +76,7 @@ func createGoTemplate(projectName, serverURL string) error {
5976
return err
6077
}
6178

62-
tmpl, err := template.New("main.go").Parse(goMainTemplate)
79+
tmpl, err := template.New("main.go").Parse(goClientMainTemplate)
6380
if err != nil {
6481
return err
6582
}
@@ -81,17 +98,18 @@ func createGoTemplate(projectName, serverURL string) error {
8198
return err
8299
}
83100

84-
func installGoLibrary(projectName, cgVersion string) error {
101+
func installGoClientLibrary(projectName, cgVersion string) error {
85102
cli.Begin("Fetching correct client library version...")
86103

87104
clientVersion := external.ClientVersionFromCGVersion("code-game-project", "go-client", cgVersion)
88105

89106
if clientVersion == "latest" {
90-
out, err := external.ExecuteInDirHidden(projectName, "go", "get")
91-
if err != nil && out != "" {
92-
cli.Error(out)
107+
var err error
108+
clientVersion, err = external.LatestGithubTag("code-game-project", "go-client")
109+
if err != nil {
110+
return err
93111
}
94-
return err
112+
clientVersion = strings.TrimPrefix(strings.Join(strings.Split(clientVersion, ".")[:2], "."), "v")
95113
}
96114

97115
majorVersion := strings.Split(clientVersion, ".")[0]
@@ -115,3 +133,148 @@ func installGoLibrary(projectName, cgVersion string) error {
115133
cli.Finish()
116134
return nil
117135
}
136+
137+
func newGoServer(projectName string) error {
138+
err := createGoServerTemplate(projectName)
139+
if err != nil {
140+
return err
141+
}
142+
143+
err = installGoServerLibrary(projectName)
144+
if err != nil {
145+
return err
146+
}
147+
148+
cli.Begin("Cleaning up...")
149+
150+
if !external.IsInstalled("goimports") {
151+
cli.Warn("Failed to add import statements: 'goimports' is not installed!")
152+
return nil
153+
}
154+
155+
external.ExecuteInDir(projectName, "goimports", "-w", "main.go")
156+
packageDir := strings.ReplaceAll(strings.ReplaceAll(projectName, "_", ""), "-", "")
157+
external.ExecuteInDir(projectName, "goimports", "-w", filepath.Join(packageDir, "game.go"))
158+
159+
out, err := external.ExecuteInDirHidden(projectName, "go", "mod", "tidy")
160+
if err != nil {
161+
if out != "" {
162+
cli.Error(out)
163+
}
164+
return err
165+
}
166+
167+
cli.Finish()
168+
169+
return nil
170+
}
171+
172+
func createGoServerTemplate(projectName string) error {
173+
module, err := cli.Input("Project module path:")
174+
if err != nil {
175+
return err
176+
}
177+
178+
cli.Begin("Creating project template...")
179+
out, err := external.ExecuteInDirHidden(projectName, "go", "mod", "init", module)
180+
if err != nil {
181+
if out != "" {
182+
cli.Error(out)
183+
}
184+
return err
185+
}
186+
187+
cgeVersion, err := external.LatestCGEVersion()
188+
if err != nil {
189+
return err
190+
}
191+
192+
err = executeGoServerTemplate(goServerMainTemplate, "main.go", projectName, cgeVersion)
193+
if err != nil {
194+
return err
195+
}
196+
197+
err = executeGoServerTemplate(goServerCGETemplate, "events.cge", projectName, cgeVersion)
198+
if err != nil {
199+
return err
200+
}
201+
202+
packageName := strings.ReplaceAll(strings.ReplaceAll(projectName, "_", ""), "-", "")
203+
204+
err = executeGoServerTemplate(goServerGameTemplate, filepath.Join(packageName, "game.go"), projectName, cgeVersion)
205+
if err != nil {
206+
return err
207+
}
208+
209+
err = executeGoServerTemplate(goServerEventsTemplate, filepath.Join(packageName, "events.go"), projectName, cgeVersion)
210+
if err != nil {
211+
return err
212+
}
213+
214+
cli.Finish()
215+
return nil
216+
}
217+
218+
func executeGoServerTemplate(templateText, fileName, projectName, cgeVersion string) error {
219+
tmpl, err := template.New(fileName).Parse(templateText)
220+
if err != nil {
221+
return err
222+
}
223+
224+
err = os.MkdirAll(filepath.Join(projectName, filepath.Dir(fileName)), 0755)
225+
if err != nil {
226+
return err
227+
}
228+
229+
file, err := os.Create(filepath.Join(projectName, fileName))
230+
if err != nil {
231+
return err
232+
}
233+
defer file.Close()
234+
235+
type data struct {
236+
Name string
237+
PackageName string
238+
SnakeCaseName string
239+
CGEVersion string
240+
}
241+
242+
return tmpl.Execute(file, data{
243+
Name: projectName,
244+
PackageName: strings.ReplaceAll(strings.ReplaceAll(projectName, "_", ""), "-", ""),
245+
SnakeCaseName: strings.ReplaceAll(projectName, "-", "_"),
246+
CGEVersion: cgeVersion,
247+
})
248+
}
249+
250+
func installGoServerLibrary(projectName string) error {
251+
cli.Begin("Fetching latest server library version...")
252+
tag, err := external.LatestGithubTag("code-game-project", "go-server")
253+
if err != nil {
254+
return err
255+
}
256+
majorVersion := strings.TrimPrefix(strings.Split(tag, ".")[0], "v")
257+
258+
path := "github.com/code-game-project/go-server/cg"
259+
if majorVersion != "0" && majorVersion != "1" {
260+
path = fmt.Sprintf("github.com/code-game-project/go-server/v%s/cg", majorVersion)
261+
}
262+
cli.Finish()
263+
264+
cli.Begin("Installing dependencies...")
265+
266+
out, err := external.ExecuteInDirHidden(projectName, "go", "get", path)
267+
if err != nil {
268+
cli.Error(out)
269+
return err
270+
}
271+
272+
out, err = external.ExecuteInDirHidden(projectName, "go", "get", "github.com/spf13/pflag")
273+
if err != nil {
274+
cli.Error(out)
275+
return err
276+
}
277+
278+
cli.Finish()
279+
return nil
280+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
name {{.SnakeCaseName}}
2+
version {{.CGEVersion}}
3+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
package {{.PackageName}}
2+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package {{.PackageName}}
2+
3+
type Game struct {
4+
cg *cg.Game
5+
}
6+
7+
func NewGame(cgGame *cg.Game) *Game {
8+
game := &Game{
9+
cg: cgGame,
10+
}
11+
return game
12+
}
13+
14+
func (g *Game) Run() {
15+
for g.cg.Running() {
16+
event, ok := g.cg.WaitForNextEvent()
17+
if !ok {
18+
break
19+
}
20+
g.handleEvent(event.Player, event.Event)
21+
}
22+
}
23+
24+
func (g *Game) handleEvent(player *cg.Player, event cg.Event) {
25+
switch event.Name {
26+
default:
27+
player.Send(player.Id, cg.EventError, cg.EventErrorData{
28+
Message: fmt.Sprintf("unexpected event: %s", event.Name),
29+
})
30+
}
31+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package main
2+
3+
func main() {
4+
var port int
5+
pflag.IntVarP(&port, "port", "p", 0, "The network port of the game server.")
6+
pflag.Parse()
7+
8+
if port == 0 {
9+
portStr, ok := os.LookupEnv("CG_PORT")
10+
if ok {
11+
port, _ = strconv.Atoi(portStr)
12+
}
13+
}
14+
15+
if port == 0 {
16+
port = 80
17+
}
18+
19+
server := cg.NewServer("{{.Name}}", cg.ServerConfig{
20+
Port: port,
21+
CGEFilepath: "events.cge",
22+
})
23+
24+
server.Run(func(cgGame *cg.Game) {
25+
{{.PackageName}}.NewGame(cgGame).Run()
26+
})
27+
}

0 commit comments

Comments
 (0)