1package server
2
3import (
4 "context"
5 "fmt"
6 "io"
7 "log/slog"
8 "net"
9 "strings"
10
11 "git.gabrielgio.me/dict/db"
12 "github.com/urfave/cli/v2"
13)
14
15var ServeCommand = &cli.Command{
16 Name: "serve",
17 Usage: "Start a simple tcp server to ansower queries",
18 Flags: []cli.Flag{
19 &cli.StringFlag{
20 Name: "addr",
21 Value: "/tmp/dict.sock",
22 Usage: "Address",
23 },
24 &cli.StringFlag{
25 Name: "database",
26 Value: "main.dict",
27 Usage: "Dictionary database location",
28 },
29 },
30 Action: func(cCtx *cli.Context) error {
31 addr := cCtx.String("addr")
32 database := cCtx.String("database")
33 return Server(context.Background(), addr, database)
34 },
35}
36
37func Server(ctx context.Context, addr, database string) error {
38 // Listen for incoming connections on port 8080
39 db, err := db.Open(database)
40 if err != nil {
41 return fmt.Errorf("Error openning datbase:%w", err)
42 }
43
44 ln, err := net.Listen("unix", addr)
45 if err != nil {
46 return err
47 }
48
49 defer ln.Close()
50
51 // Accept incoming connections and handle them
52 for {
53 conn, err := ln.Accept()
54 if err != nil {
55 slog.Error("Error accepting conn", "error", err)
56 continue
57 }
58
59 slog.Info("Connection accepeted")
60 go handleConnection(conn, db)
61 }
62}
63
64func handleConnection(conn net.Conn, db *db.DB) {
65 defer conn.Close()
66
67 // Read incoming data
68 buf := make([]byte, 0, 4096) // big buffer
69 tmp := make([]byte, 256) // using small tmo buffer for demonstrating
70 for {
71 n, err := conn.Read(tmp)
72 if err != nil {
73 if err != io.EOF {
74 slog.Error("Error reading conn", "error", err)
75 return
76 }
77 break
78 }
79 buf = append(buf, tmp[:n]...)
80
81 }
82
83 q := strings.ReplaceAll(string(buf), "\n", "")
84
85 ws, err := db.SelectDict(context.Background(), q, 10)
86 if err != nil {
87 slog.Error("Error selecting", "error", err)
88 return
89 }
90
91 for _, w := range ws {
92 fmt.Fprintf(conn, "%s\n%s\n\n", w.Word, w.Line)
93 }
94}