-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgo-graph.go
154 lines (130 loc) · 3.54 KB
/
go-graph.go
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package main
import (
"database/sql"
"flag"
"fmt"
"go/build"
"log"
"net/http"
"path/filepath"
"github.com/gorilla/websocket"
_ "github.com/mattn/go-sqlite3" //no name needed as it implements the database/sql interface
"github.com/ugorji/go/codec"
)
type Context struct {
db *sql.DB
mh codec.Handle
}
func (c *Context) Close() {
c.db.Close()
}
func NewContext(db_path string) *Context {
db, err := sql.Open("sqlite3", db_path)
if err != nil {
log.Fatal("DB connection failed with path:", db_path)
}
if err = db.Ping(); err != nil {
log.Fatal("Couldn't ping the DB at:", db_path)
}
return &Context{db, new(codec.MsgpackHandle)}
}
type contextHandler struct {
ctx *Context
h handler
}
type handler func(http.ResponseWriter, *http.Request, *Context)
func (ch contextHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
ch.h(w, req, ch.ctx)
}
func defaultAssetPath() string {
p, err := build.Default.Import("github.com/Blackth0rn/go-graph/public", "", build.FindOnly)
if err != nil {
return "."
}
return p.Dir
}
func homeHandler(c http.ResponseWriter, req *http.Request, ctx *Context) {
http.ServeFile(c, req, filepath.Join(*assets, "index.html"))
}
func wsHandler(w http.ResponseWriter, r *http.Request, ctx *Context) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
return
}
// use ws to send/receive messages
for {
messageType, p, err := ws.ReadMessage()
if err != nil {
return
}
var output []byte
msg_type := p[0]
payload := p[1:]
switch msg_type {
case add_link:
output, _ = addLink(payload, ctx)
case send_list:
log.Println("sendList")
output, _ = sendList(payload, ctx)
log.Println(output)
}
output = append([]byte{msg_type}, output...)
if err = ws.WriteMessage(messageType, output); err != nil {
fmt.Println(err)
return
}
}
}
var (
addr *string = flag.String("addr", ":8080", "http service address")
assets *string = flag.String("assets", defaultAssetPath(), "path to assets")
upgrader *websocket.Upgrader = &websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
)
const (
err = iota // 0
add_link // 1
send_list // 2
clear_list // 3
)
func main() {
db_path := flag.String("dbpath", "./go-graph.db", "path to db file")
action := flag.String("action", "", "action to take: init (wipe and initialize db), clear (clear db)")
flag.Parse()
// Setup a file server at the default asset path
fs := http.FileServer(http.Dir(defaultAssetPath()))
c := NewContext(*db_path)
defer c.Close()
switch *action {
case "init":
//Init DB
var err error
_, err = c.db.Exec("DROP TABLE IF EXISTS links")
if err != nil {
log.Fatal("Failed to drop the links table: ", err)
}
_, err = c.db.Exec("CREATE TABLE links (start_layout TEXT, action TEXT, end_layout TEXT, CONSTRAINT unique_link UNIQUE (start_layout, action, end_layout))")
if err != nil {
log.Fatal("Failed to create the links table: ", err)
}
case "clear":
//Clear DB
var err error
_, err = c.db.Exec("DELETE FROM links")
if err != nil {
log.Fatal("Failed to clear the links table: ", err)
}
}
// handle all /public/ locations via the file server
http.Handle("/public/", http.StripPrefix("/public/", fs))
// Returns the index.html file
http.Handle("/", contextHandler{c, homeHandler})
// Handles all websocket connections
http.Handle("/ws", contextHandler{c, wsHandler})
log.Println("Starting a server on:", *addr)
if err := http.ListenAndServe(*addr, nil); err != nil {
log.Fatal("ListenAndServe:", err)
}
}