aboutsummaryrefslogtreecommitdiff
path: root/server/main.go
blob: 4737f177ae1707c0caae0e0c4e4a29833925b894 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package main

import (
	"embed"
	"flag"
	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
	"database/sql"
	"log"
	"math/rand"
	"net/http"
	"time"

	_ "github.com/mattn/go-sqlite3"
)

var db *sql.DB
var dbFilePath string
var port string

type Bin struct {
	Content  string `json:"content"`
	Language string `json:"language"`
}

const (
	shortIDCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	shortIDLength  = 8
)

var (
	//go:embed all:dist
	dist embed.FS
)

func RegisterHandlers(e *echo.Echo) {
	e.Use(middleware.StaticWithConfig(middleware.StaticConfig{
		Skipper: nil,
		Root: "dist",
		Index: "index.html",
		HTML5:      true,
		Filesystem: http.FS(dist),
	}))
	e.Use(middleware.CORS())
	e.POST("/bin", postBin)
	e.GET("/bin/:id", getBin)
}

func main() {
	flag.StringVar(&port, "port", "8080", "HTTP server port")
	flag.StringVar(&dbFilePath, "db", "minibin.db", "Path to SQLite database file")
	flag.Parse()

	initDatabase()
	e := echo.New()
	RegisterHandlers(e)
	e.Logger.Fatal(e.Start(":" + port))
}

func initDatabase() {
	var err error
	db, err = sql.Open("sqlite3", dbFilePath)
	if err != nil {
		log.Fatal(err)
	}

	err = createTable()
	if err != nil {
		log.Fatal(err)
	}
}

func postBin(echoContext echo.Context) error {
	bin := Bin{}
	err := echoContext.Bind(&bin)
	if err != nil {
		return err
	}
	id := generateShortID()
	err = saveBin(id, bin)
	if err != nil {
		return err
	}
	return echoContext.JSON(http.StatusCreated, echo.Map{
		"id": id,
	})
}

func getBin(echoContext echo.Context) error {
	id := echoContext.Param("id")
	bin, err := getBinById(id)
	if err != nil {
		return err
	}
	return echoContext.JSON(http.StatusOK, bin)
}

func createTable() error {
	_, err := db.Exec("CREATE TABLE IF NOT EXISTS bins (id TEXT PRIMARY KEY, content TEXT, language TEXT)")
	return err
}

func getBinById(id string) (Bin, error) {
	row := db.QueryRow("SELECT content, language FROM bins WHERE id = ?", id)
	bin := Bin{}
	err := row.Scan(&bin.Content, &bin.Language)
	return bin, err
}

func saveBin(id string, bin Bin) error {
	_, err := db.Exec("INSERT INTO bins (id, content, language) VALUES (?, ?, ?)", id, bin.Content, bin.Language)
	return err
}

func generateShortID() string {
	rand.Seed(time.Now().UnixNano())
	id := make([]byte, shortIDLength)
	for i := range id {
		id[i] = shortIDCharset[rand.Intn(len(shortIDCharset))]
	}
	return string(id)
}