At heart, this program is just the basic "FizzBuzz" program. However, the program was pushed further, by making it a client-server via Unix Socket:
- Server run, and listening on a socket.
- Client run with an argument, a file containing a JSON one query or more. The client opens the file and takes the queries.
- A typical JSON query would look like this: {"id":"first attempt","from":0,"to":15,"fizz":"Mango","buzz":"Avocado"}\n and is sent through the unix socket file to the server.
- The server receives the JSON message perform the FizzBuzz, and send an answer back to client (also JSON form). {"first attempt":["MangoAvocado",1,2,"Mango",4,"Avocado","Mango",7,8,"Mango","Avocado",11,"Mango",13,14,"MangoAvocado"]}
- Client receives the JSON message and printout the JSON elements:
Here is the server.go
:
package main
import (
"log"
"net"
"os"
"os/signal"
"syscall"
"encoding/json"
)
//thanks to https://mholt.github.io/json-to-go/
type input struct {
ID string `json:"id"`
From int `json:"from"`
To int `json:"to"`
Fizz string `json:"fizz"`
Buzz string `json:"buzz"`
}
type output struct {
Output []interface{} `json:"output"`
}
func nice(inputBytes []byte)[]byte{
var in input
json.Unmarshal(inputBytes, &in)
out := output{
Output: []interface{}{},
}
for i := in.From; i <= in.To; i++ {
if i % 3 == 0 {
if i % 5 == 0{
out.Output = append(out.Output, in.Fizz + in.Buzz)
}else{
out.Output = append(out.Output, in.Fizz)
}
}else if i % 5 == 0{
out.Output = append(out.Output, in.Buzz)
}else{
out.Output = append(out.Output, i)
}
}
d, _ := json.Marshal(out.Output)
d = append([]byte("\":"), d...)
d = append([]byte(in.ID), d...)
d = append([]byte("{\""), d...)
d = append(d, "}"...)
return d
}
func echoServer(c net.Conn) {
for {
buf := make([]byte, 512)
nr, err := c.Read(buf)
if err != nil {
return
}
data := buf[0:nr]
println("Server got:", string(data))
data = nice(data)
_, err = c.Write(data)
if err != nil {
log.Fatal("Writing client error: ", err)
}
}
}
func main() {
log.Println("Starting echo server")
ln, err := net.Listen("unix", "/tmp/go.sock")
if err != nil {
log.Fatal("Listen error: ", err)
}
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, os.Interrupt, syscall.SIGTERM)
go func(ln net.Listener, c chan os.Signal) {
sig := <-c
log.Printf("Caught signal %s: shutting down.", sig)
ln.Close()
os.Exit(0)
}(ln, sigc)
for {
fd, err := ln.Accept()
if err != nil {
log.Fatal("Accept error: ", err)
}
go echoServer(fd)
}
}
and the client.go
:
package main
import (
"fmt"
"os"
"bufio"
"io"
"log"
"net"
"time"
)
func reader(r io.Reader) {
buf := make([]byte, 1024)
for {
n, err := r.Read(buf[:])
if err != nil {
return
}
println("Client got:", string(buf[0:n]))
}
}
func main() {
if len(os.Args) <= 1 {
fmt.Println("No args given. (expecting a filename)")
return
}
if len(os.Args) > 2 {
fmt.Println("Too many args (only expecting one)")
return
}
var file, err = os.OpenFile(os.Args[1], os.O_RDONLY, 0644)
if (err != nil){
log.Fatal(err) //problem opening filename
return
}
defer file.Close()
scanner := bufio.NewScanner(file)
msg := ""
c, err := net.Dial("unix", "/tmp/go.sock")
if err != nil {
log.Fatal("Dial error", err)
}
defer c.Close()
go reader(c)
for scanner.Scan(){
msg = scanner.Text()
_, err = c.Write([]byte(msg))
if err != nil {
log.Fatal("Write error:", err)
//break
return
}
println("Client sent:", msg)
time.Sleep(1e9) // this gives time for
}
if err:=scanner.Err(); err != nil{
log.Fatal(err)
}
}
Say, we have this file named input
:
{"id":"first entry","from":0,"to":15,"fizz":"Orca","buzz":"Seal"}
{"id":"second entry","from":-3,"to":8,"fizz":"Mango","buzz":"Avocado"}
{"id":"third one","from":1001,"to":1025,"fizz":"Coke","buzz":"Pepsi"}
Running go run server.go
and go run client.go input
will give these:
Client sent: {"id":"first entry","from":0,"to":15,"fizz":"Orca","buzz":"Seal"}
Client got: {"first entry":["OrcaSeal",1,2,"Orca",4,"Seal","Orca",7,8,"Orca","Seal",11,"Orca",13,14,"OrcaSeal"]}
Client sent: {"id":"second entry","from":-3,"to":8,"fizz":"Mango","buzz":"Avocado"}
Client got: {"second entry":["Mango",-2,-1,"MangoAvocado",1,2,"Mango",4,"Avocado","Mango",7,8]}
Client sent: {"id":"third one","from":1001,"to":1025,"fizz":"Coke","buzz":"Pepsi"}
Client got: {"third one":[1001,"Coke",1003,1004,"CokePepsi",1006,1007,"Coke",1009,"Pepsi","Coke",1012,1013,"Coke","Pepsi",1016,"Coke",1018,1019,"CokePepsi",1021,1022,"Coke",1024,"Pepsi"]}
This program works as expected but I am somehow not satisfied since I am new to both JSON and Go. How can I improve the code?