Working on server app

This commit is contained in:
Brian Buller 2016-02-22 21:23:53 -06:00
parent 32f6cf6e1d
commit 0f75137097
6 changed files with 315 additions and 13 deletions

View 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)
}

View File

@ -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
View 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,
}
}

View 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
}

View 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)
})
}
}

View File

@ -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
}