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"
|
"errors"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/br0xen/boltrest"
|
"github.com/br0xen/boltrest"
|
||||||
|
"github.com/nsf/termbox-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
var adminDB *boltrest.DB
|
var adminDB *boltrest.DB
|
||||||
@ -13,10 +16,60 @@ var adminDB *boltrest.DB
|
|||||||
func main() {
|
func main() {
|
||||||
initialize()
|
initialize()
|
||||||
adminDB = boltrest.Open("admin.db")
|
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() {
|
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 {
|
func initialize() error {
|
||||||
@ -42,6 +95,25 @@ func initialize() error {
|
|||||||
return nil
|
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"
|
const keyChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||||
|
|
||||||
func generateAPIKey() string {
|
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"
|
"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
|
// in a local bolt db and a remote db through a
|
||||||
// rest api.
|
// rest api.
|
||||||
|
|
||||||
@ -34,12 +34,20 @@ func Open(filename string) (*DB, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// Go ahead and make sure it's fresh
|
||||||
|
b.RefreshDB()
|
||||||
return &b, nil
|
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
|
// MkBucketPath builds all buckets in the string slice
|
||||||
func (b *DB) MkBucketPath(path []string) error {
|
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 {
|
err := b.localDB.Update(func(tx *bolt.Tx) error {
|
||||||
var err error
|
var err error
|
||||||
bkt := tx.Bucket([]byte(path[0]))
|
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) {
|
func (b *DB) GetValue(path []string, key string) (string, error) {
|
||||||
var err error
|
var err error
|
||||||
var ret string
|
var ret string
|
||||||
// TODO: Make sure local db is fresh (or offline)
|
b.RefreshDB()
|
||||||
|
|
||||||
b.localDB.View(func(tx *bolt.Tx) error {
|
b.localDB.View(func(tx *bolt.Tx) error {
|
||||||
bkt := tx.Bucket([]byte(path[0]))
|
bkt := tx.Bucket([]byte(path[0]))
|
||||||
if bkt == nil {
|
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
|
// SetValue sets the value at path to val
|
||||||
// path is a slice of tokens
|
// path is a slice of tokens
|
||||||
func (b *DB) SetValue(path []string, key, val string) error {
|
func (b *DB) SetValue(path []string, key, val string) error {
|
||||||
|
b.RefreshDB()
|
||||||
err := b.MkBucketPath(path)
|
err := b.MkBucketPath(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
// GetBucketList returns a list of all sub-buckets at path
|
||||||
func (b *DB) GetBucketList(path []string) ([]string, error) {
|
func (b *DB) GetBucketList(path []string) ([]string, error) {
|
||||||
|
b.RefreshDB()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
var ret []string
|
var ret []string
|
||||||
// TODO: Make sure local db is fresh (or offline)
|
|
||||||
|
|
||||||
err = b.localDB.Update(func(tx *bolt.Tx) error {
|
err = b.localDB.Update(func(tx *bolt.Tx) error {
|
||||||
bkt := tx.Bucket([]byte(path[0]))
|
bkt := tx.Bucket([]byte(path[0]))
|
||||||
if bkt == nil {
|
if bkt == nil {
|
||||||
@ -216,10 +224,10 @@ func (b *DB) GetBucketList(path []string) ([]string, error) {
|
|||||||
|
|
||||||
// GetKeyList returns a list of all keys at path
|
// GetKeyList returns a list of all keys at path
|
||||||
func (b *DB) GetKeyList(path []string) ([]string, error) {
|
func (b *DB) GetKeyList(path []string) ([]string, error) {
|
||||||
|
b.RefreshDB()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
var ret []string
|
var ret []string
|
||||||
// TODO: Make sure local db is fresh (or offline)
|
|
||||||
|
|
||||||
err = b.localDB.Update(func(tx *bolt.Tx) error {
|
err = b.localDB.Update(func(tx *bolt.Tx) error {
|
||||||
bkt := tx.Bucket([]byte(path[0]))
|
bkt := tx.Bucket([]byte(path[0]))
|
||||||
if bkt == nil {
|
if bkt == nil {
|
||||||
@ -250,9 +258,8 @@ func (b *DB) GetKeyList(path []string) ([]string, error) {
|
|||||||
|
|
||||||
// DeletePair deletes the pair with key at path
|
// DeletePair deletes the pair with key at path
|
||||||
func (b *DB) DeletePair(path []string, key string) error {
|
func (b *DB) DeletePair(path []string, key string) error {
|
||||||
|
b.RefreshDB()
|
||||||
var err error
|
var err error
|
||||||
// TODO: Make sure local db is fresh (or offline)
|
|
||||||
|
|
||||||
err = b.localDB.Update(func(tx *bolt.Tx) error {
|
err = b.localDB.Update(func(tx *bolt.Tx) error {
|
||||||
bkt := tx.Bucket([]byte(path[0]))
|
bkt := tx.Bucket([]byte(path[0]))
|
||||||
if bkt == nil {
|
if bkt == nil {
|
||||||
@ -280,9 +287,8 @@ func (b *DB) DeletePair(path []string, key string) error {
|
|||||||
|
|
||||||
// DeleteBucket deletes the bucket key at path
|
// DeleteBucket deletes the bucket key at path
|
||||||
func (b *DB) DeleteBucket(path []string, key string) error {
|
func (b *DB) DeleteBucket(path []string, key string) error {
|
||||||
|
b.RefreshDB()
|
||||||
var err error
|
var err error
|
||||||
// TODO: Make sure local db is fresh (or offline)
|
|
||||||
|
|
||||||
err = b.localDB.Update(func(tx *bolt.Tx) error {
|
err = b.localDB.Update(func(tx *bolt.Tx) error {
|
||||||
bkt := tx.Bucket([]byte(path[0]))
|
bkt := tx.Bucket([]byte(path[0]))
|
||||||
if bkt == nil {
|
if bkt == nil {
|
||||||
@ -305,6 +311,15 @@ func (b *DB) DeleteBucket(path []string, key string) error {
|
|||||||
return err
|
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 {
|
type setURLResponse struct {
|
||||||
dbMD5 string
|
dbMD5 string
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user