Working on server app
This commit is contained in:
parent
32f6cf6e1d
commit
0f75137097
21
boltrest-server/about_screen.go
Normal file
21
boltrest-server/about_screen.go
Normal file
@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/br0xen/termbox-util"
|
||||
"github.com/nsf/termbox-go"
|
||||
)
|
||||
|
||||
// AboutScreen is the about screen
|
||||
type AboutScreen struct{}
|
||||
|
||||
func (screen *AboutScreen) handleEvent(event termbox.Event) int {
|
||||
return ServerScreenIndex
|
||||
}
|
||||
|
||||
func (screen *AboutScreen) performLayout(style Style) {}
|
||||
|
||||
func (screen *AboutScreen) drawScreen(style Style) {
|
||||
width, height := termbox.Size()
|
||||
exitTxt := "Press any key to exit help"
|
||||
termboxUtil.DrawStringAtPoint(exitTxt, (width-len(exitTxt))/2, height-1, style.titleFg, style.titleBg)
|
||||
}
|
@ -4,8 +4,11 @@ import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/br0xen/boltrest"
|
||||
"github.com/nsf/termbox-go"
|
||||
)
|
||||
|
||||
var adminDB *boltrest.DB
|
||||
@ -13,10 +16,60 @@ var adminDB *boltrest.DB
|
||||
func main() {
|
||||
initialize()
|
||||
adminDB = boltrest.Open("admin.db")
|
||||
|
||||
err := termbox.Init()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer termbox.Close()
|
||||
stl := getDefaultStyle()
|
||||
termbox.SetOutputMode(termbox.Output256)
|
||||
mainLoop(stl)
|
||||
}
|
||||
|
||||
func mainLoop() {
|
||||
|
||||
screens := defaultScreens()
|
||||
displayScreen := screens[NasomiScreenIndex]
|
||||
layoutAndDrawScreen(displayScreen, stl)
|
||||
eventChan := make(chan termbox.Event)
|
||||
go readUserInput(eventChan)
|
||||
go sendNoneEvent(eventChan)
|
||||
for {
|
||||
event := <-eventChan
|
||||
if event.Type == termbox.EventKey {
|
||||
if event.Key == termbox.KeyCtrlZ {
|
||||
process, _ := os.FindProcess(os.Getpid())
|
||||
termbox.Close()
|
||||
process.Signal(syscall.SIGSTOP)
|
||||
termbox.Init()
|
||||
} else if event.Key == termbox.KeyCtrlC {
|
||||
termbox.Close()
|
||||
os.Exit(0)
|
||||
}
|
||||
newScreenIndex := displayScreen.handleKeyEvent(event)
|
||||
if newScreenIndex < len(screens) {
|
||||
displayScreen = screens[newScreenIndex]
|
||||
layoutAndDrawScreen(displayScreen, stl)
|
||||
} else {
|
||||
termbox.Close()
|
||||
break
|
||||
}
|
||||
}
|
||||
if event.Type == termbox.EventResize || event.Type == termbox.EventNone {
|
||||
layoutAndDrawScreen(displayScreen, stl)
|
||||
}
|
||||
}
|
||||
}
|
||||
func readUserInput(e chan termbox.Event) {
|
||||
for {
|
||||
e <- termbox.PollEvent()
|
||||
}
|
||||
}
|
||||
func sendNoneEvent(e chan termbox.Event) {
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
e <- termbox.Event{Type: termbox.EventNone}
|
||||
}
|
||||
}
|
||||
|
||||
func initialize() error {
|
||||
@ -42,6 +95,25 @@ func initialize() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
// ServerScreenIndex is the index
|
||||
ServerScreenIndex = iota
|
||||
// AboutScreenIndex The idx number for the 'About' Screen
|
||||
AboutScreenIndex
|
||||
// ExitScreenIndex The idx number for Exiting
|
||||
ExitScreenIndex
|
||||
)
|
||||
|
||||
func defaultScreens() []Screen {
|
||||
serverScreen := ServerScreen{}
|
||||
aboutScreen := AboutScreen{}
|
||||
screens := []Screen{
|
||||
&serverScreen,
|
||||
&aboutScreen,
|
||||
}
|
||||
return screens
|
||||
}
|
||||
|
||||
const keyChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
|
||||
func generateAPIKey() string {
|
||||
|
42
boltrest-server/screen.go
Normal file
42
boltrest-server/screen.go
Normal file
@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import "github.com/nsf/termbox-go"
|
||||
|
||||
// Screen is a basic structure for all of the applications screens
|
||||
type Screen interface {
|
||||
handleKeyEvent(event termbox.Event) int
|
||||
performLayout(style Style)
|
||||
drawScreen(style Style)
|
||||
}
|
||||
|
||||
func drawBackground(bg termbox.Attribute) {
|
||||
termbox.Clear(0, bg)
|
||||
}
|
||||
|
||||
func layoutAndDrawScreen(screen Screen, style Style) {
|
||||
screen.performLayout(style)
|
||||
drawBackground(style.defaultBg)
|
||||
screen.drawScreen(style)
|
||||
termbox.Flush()
|
||||
}
|
||||
|
||||
// Style defines style for a screen
|
||||
type Style struct {
|
||||
defaultBg termbox.Attribute
|
||||
defaultFg termbox.Attribute
|
||||
titleFg termbox.Attribute
|
||||
titleBg termbox.Attribute
|
||||
cursorFg termbox.Attribute
|
||||
cursorBg termbox.Attribute
|
||||
}
|
||||
|
||||
func getDefaultStyle() Style {
|
||||
return Style{
|
||||
defaultBg: termbox.ColorBlack,
|
||||
defaultFg: termbox.ColorWhite,
|
||||
titleBg: termbox.ColorBlack,
|
||||
titleFg: termbox.ColorGreen,
|
||||
cursorBg: termbox.ColorWhite,
|
||||
cursorFg: termbox.ColorBlack,
|
||||
}
|
||||
}
|
75
boltrest-server/server_screen.go
Normal file
75
boltrest-server/server_screen.go
Normal file
@ -0,0 +1,75 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/br0xen/termbox-util"
|
||||
"github.com/nsf/termbox-go"
|
||||
)
|
||||
|
||||
// ServerScreen holds all that's going on :D
|
||||
type ServerScreen struct {
|
||||
initialized bool
|
||||
|
||||
message string
|
||||
messageTime time.Time
|
||||
messageTimeout time.Duration
|
||||
tabIdx int
|
||||
}
|
||||
|
||||
func (screen *ServerScreen) handleEvent(event termbox.Event) int {
|
||||
_, h := termbox.Size()
|
||||
if event.Type == termbox.EventKey {
|
||||
}
|
||||
return ServerScreenIndex
|
||||
}
|
||||
|
||||
func (screen *ServerScreen) performLayout(style Style) {
|
||||
w, h := termbox.Size()
|
||||
if !screen.initialized {
|
||||
}
|
||||
|
||||
if screen.messageTimeout > 0 && time.Since(screen.messageTime) > screen.messageTimeout {
|
||||
screen.clearMessage()
|
||||
msgString := ""
|
||||
msgString = termboxUtil.AlignText(msgString, w, termboxUtil.AlignLeft)
|
||||
screen.setMessage(msgString)
|
||||
}
|
||||
}
|
||||
|
||||
func (screen *ServerScreen) drawScreen(style Style) {
|
||||
w, h := termbox.Size()
|
||||
screen.drawHeader(style)
|
||||
screen.drawFooter(style)
|
||||
}
|
||||
|
||||
func (screen *ServerScreen) drawHeader(style Style) {
|
||||
w, _ := termbox.Size()
|
||||
ttl := termboxUtil.AlignTextWithFill("Boltrest Server", w+1, termboxUtil.AlignCenter, '=')
|
||||
termboxUtil.DrawStringAtPoint(ttl, 0, 0, style.defaultBg, style.defaultFg)
|
||||
}
|
||||
|
||||
func (screen *ServerScreen) drawFooter(style Style) {
|
||||
_, height := termbox.Size()
|
||||
termboxUtil.DrawStringAtPoint(screen.message, 0, height-1, style.defaultBg, style.defaultFg)
|
||||
}
|
||||
|
||||
func (screen *ServerScreen) setMessage(msg string) {
|
||||
screen.message = msg
|
||||
screen.messageTime = time.Now()
|
||||
screen.messageTimeout = -1
|
||||
}
|
||||
|
||||
/* setMessageWithTimeout lets you specify the timeout for the message
|
||||
* setting it to -1 means it won't timeout
|
||||
*/
|
||||
func (screen *ServerScreen) setMessageWithTimeout(msg string, timeout time.Duration) {
|
||||
screen.message = msg
|
||||
screen.messageTime = time.Now()
|
||||
screen.messageTimeout = timeout
|
||||
}
|
||||
|
||||
func (screen *ServerScreen) clearMessage() {
|
||||
screen.message = ""
|
||||
screen.messageTimeout = -1
|
||||
}
|
77
boltrest-server/web_server.go
Normal file
77
boltrest-server/web_server.go
Normal file
@ -0,0 +1,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/devict/magopie"
|
||||
"github.com/devict/magopie/vendor/github.com/gorilla/mux"
|
||||
"github.com/devict/magopie/vendor/github.com/justinas/alice"
|
||||
)
|
||||
|
||||
// WebServer ...
|
||||
type WebServer struct {
|
||||
addr string
|
||||
tlsCert string
|
||||
tlsKey string
|
||||
|
||||
adminMode bool
|
||||
}
|
||||
|
||||
// Listen makes it listen for connetions
|
||||
func (s *WebServer) Listen() {
|
||||
if s.tlsCert != "" && s.tlsKey != "" {
|
||||
log.Printf("Listening for HTTPS on %s with key %s and cert %s", s.addr, s.tlsKey, s.tlsCert)
|
||||
log.Fatal(http.ListenAndServeTLS(s.addr, s.tlsCert, s.tlsKey, s.router(a)))
|
||||
} else {
|
||||
log.Printf("Listening for HTTP on %s", *addr)
|
||||
log.Fatal(http.ListenAndServe(*addr, s.router(a)))
|
||||
}
|
||||
}
|
||||
|
||||
// Router defines all of the routes
|
||||
func (s *WebServer) Router() http.Handler {
|
||||
r := mux.NewRouter()
|
||||
|
||||
r.HandleFunc("/", s.handleAllSites).Methods("GET")
|
||||
r.HandleFunc("/genAPIKey/{db}", s.genAPIKey).Methods("POST")
|
||||
|
||||
chain := alice.New(mwLogger, mwAuthenticationCheck(a.key)).Then(r)
|
||||
|
||||
return chain
|
||||
}
|
||||
|
||||
func (s *WebServer) handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
err := json.NewEncoder(w).Encode()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *WebServer) genAPIKey(w http.ResponseWriter, r *http.Request) {
|
||||
err := json.NewEncoder(w).Encode()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *WebServer) mwLogger(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
log.Println("Serving", r.Method, r.URL.String(), "to", r.RemoteAddr)
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *WebServer) mwAuthenticationCheck(key string) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !magopie.CheckMAC(r.Header.Get("X-Request-ID"), r.Header.Get("X-HMAC"), key) {
|
||||
log.Println("Request failed HMAC")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
39
boltrest.go
39
boltrest.go
@ -12,7 +12,7 @@ import (
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
// This a custom library for saving/syncing data
|
||||
// This is a custom library for saving/syncing data
|
||||
// in a local bolt db and a remote db through a
|
||||
// rest api.
|
||||
|
||||
@ -34,12 +34,20 @@ func Open(filename string) (*DB, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Go ahead and make sure it's fresh
|
||||
b.RefreshDB()
|
||||
return &b, nil
|
||||
}
|
||||
|
||||
// Offline sets this DB to offline mode
|
||||
// That means it won't try to sync anything
|
||||
func (b *DB) Offline() {
|
||||
b.online = false
|
||||
}
|
||||
|
||||
// MkBucketPath builds all buckets in the string slice
|
||||
func (b *DB) MkBucketPath(path []string) error {
|
||||
// TODO: Make sure local db is fresh (or offline)
|
||||
b.RefreshDB()
|
||||
err := b.localDB.Update(func(tx *bolt.Tx) error {
|
||||
var err error
|
||||
bkt := tx.Bucket([]byte(path[0]))
|
||||
@ -76,8 +84,7 @@ func (b *DB) MkBucketPath(path []string) error {
|
||||
func (b *DB) GetValue(path []string, key string) (string, error) {
|
||||
var err error
|
||||
var ret string
|
||||
// TODO: Make sure local db is fresh (or offline)
|
||||
|
||||
b.RefreshDB()
|
||||
b.localDB.View(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket([]byte(path[0]))
|
||||
if bkt == nil {
|
||||
@ -100,6 +107,7 @@ func (b *DB) GetValue(path []string, key string) (string, error) {
|
||||
// SetValue sets the value at path to val
|
||||
// path is a slice of tokens
|
||||
func (b *DB) SetValue(path []string, key, val string) error {
|
||||
b.RefreshDB()
|
||||
err := b.MkBucketPath(path)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -180,10 +188,10 @@ func (b *DB) SetTimestamp(path []string, key string, val time.Time) error {
|
||||
|
||||
// GetBucketList returns a list of all sub-buckets at path
|
||||
func (b *DB) GetBucketList(path []string) ([]string, error) {
|
||||
b.RefreshDB()
|
||||
|
||||
var err error
|
||||
var ret []string
|
||||
// TODO: Make sure local db is fresh (or offline)
|
||||
|
||||
err = b.localDB.Update(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket([]byte(path[0]))
|
||||
if bkt == nil {
|
||||
@ -216,10 +224,10 @@ func (b *DB) GetBucketList(path []string) ([]string, error) {
|
||||
|
||||
// GetKeyList returns a list of all keys at path
|
||||
func (b *DB) GetKeyList(path []string) ([]string, error) {
|
||||
b.RefreshDB()
|
||||
|
||||
var err error
|
||||
var ret []string
|
||||
// TODO: Make sure local db is fresh (or offline)
|
||||
|
||||
err = b.localDB.Update(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket([]byte(path[0]))
|
||||
if bkt == nil {
|
||||
@ -250,9 +258,8 @@ func (b *DB) GetKeyList(path []string) ([]string, error) {
|
||||
|
||||
// DeletePair deletes the pair with key at path
|
||||
func (b *DB) DeletePair(path []string, key string) error {
|
||||
b.RefreshDB()
|
||||
var err error
|
||||
// TODO: Make sure local db is fresh (or offline)
|
||||
|
||||
err = b.localDB.Update(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket([]byte(path[0]))
|
||||
if bkt == nil {
|
||||
@ -280,9 +287,8 @@ func (b *DB) DeletePair(path []string, key string) error {
|
||||
|
||||
// DeleteBucket deletes the bucket key at path
|
||||
func (b *DB) DeleteBucket(path []string, key string) error {
|
||||
b.RefreshDB()
|
||||
var err error
|
||||
// TODO: Make sure local db is fresh (or offline)
|
||||
|
||||
err = b.localDB.Update(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket([]byte(path[0]))
|
||||
if bkt == nil {
|
||||
@ -305,6 +311,15 @@ func (b *DB) DeleteBucket(path []string, key string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// RefreshDB makes sure that the DB is fresh with the server version
|
||||
func (b *DB) RefreshDB() error {
|
||||
var err error
|
||||
if b.online {
|
||||
// TODO: Compare latest change here with lates on server
|
||||
// Then sync, if needed
|
||||
}
|
||||
}
|
||||
|
||||
type setURLResponse struct {
|
||||
dbMD5 string
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user