mirror of
https://github.com/safing/portbase
synced 2025-09-04 19:50:18 +00:00
Remove old api
This commit is contained in:
parent
60dbbe55e9
commit
0318521ca5
8 changed files with 0 additions and 545 deletions
|
@ -1,76 +0,0 @@
|
||||||
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
_ "github.com/Safing/safing-core/configuration"
|
|
||||||
"github.com/Safing/safing-core/database"
|
|
||||||
"github.com/Safing/safing-core/formats/dsd"
|
|
||||||
|
|
||||||
"github.com/ipfs/go-datastore"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Get(session *Session, key string) {
|
|
||||||
iterator, err := database.EasyQueryIterator(key)
|
|
||||||
if err != nil {
|
|
||||||
handleError(session, fmt.Sprintf("error|500|could not query: %s", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var returnedStuff bool
|
|
||||||
|
|
||||||
for obj, ok := iterator.NextSync(); ok; obj, ok = iterator.NextSync() {
|
|
||||||
bytes, err := database.DumpModel(obj.Value, dsd.JSON)
|
|
||||||
|
|
||||||
returnedStuff = true
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
toSend := []byte(fmt.Sprintf("current|%s|%s", obj.Key, string(bytes)))
|
|
||||||
session.send <- toSend
|
|
||||||
} else {
|
|
||||||
handleError(session, fmt.Sprintf("error|500|dump failed: %s", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !returnedStuff {
|
|
||||||
handleError(session, "error|400|no results: "+key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Subscribe(session *Session, key string) {
|
|
||||||
session.Subscribe(key)
|
|
||||||
Get(session, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Unsubscribe(session *Session, key string) {
|
|
||||||
session.Unsubscribe(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Save(session *Session, key string, create bool, data []byte) {
|
|
||||||
var model database.Model
|
|
||||||
var err error
|
|
||||||
dbKey := datastore.NewKey(key)
|
|
||||||
model, err = database.NewWrapper(&dbKey, data)
|
|
||||||
if err != nil {
|
|
||||||
handleError(session, fmt.Sprintf("error|500|failed to wrap object: %s", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if create {
|
|
||||||
err = database.Create(dbKey, model)
|
|
||||||
} else {
|
|
||||||
err = database.Update(dbKey, model)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
handleError(session, fmt.Sprintf("error|500|failed to save to database: %s", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Delete(session *Session, key string) {
|
|
||||||
dbKey := datastore.NewKey(key)
|
|
||||||
err := database.Delete(dbKey)
|
|
||||||
if err != nil {
|
|
||||||
handleError(session, fmt.Sprintf("error|500|failed to delete from database: %s", err))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/Safing/safing-core/log"
|
|
||||||
"github.com/Safing/safing-core/modules"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
apiModule *modules.Module
|
|
||||||
apiAddress = ":18"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Start() {
|
|
||||||
apiModule = modules.Register("Api", 32)
|
|
||||||
|
|
||||||
go run()
|
|
||||||
|
|
||||||
<-apiModule.Stop
|
|
||||||
apiModule.StopComplete()
|
|
||||||
}
|
|
||||||
|
|
||||||
func run() {
|
|
||||||
router := NewRouter()
|
|
||||||
|
|
||||||
log.Infof("api: starting to listen on %s", apiAddress)
|
|
||||||
log.Errorf("api: listener failed: %s", http.ListenAndServe(apiAddress, router))
|
|
||||||
}
|
|
|
@ -1,120 +0,0 @@
|
||||||
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/Safing/safing-core/log"
|
|
||||||
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
)
|
|
||||||
|
|
||||||
func allowAnyOrigin(r *http.Request) bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func apiVersionOneHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
|
|
||||||
upgrader := websocket.Upgrader{
|
|
||||||
CheckOrigin: allowAnyOrigin,
|
|
||||||
ReadBufferSize: 1024,
|
|
||||||
WriteBufferSize: 65536,
|
|
||||||
}
|
|
||||||
wsConn, err := upgrader.Upgrade(w, r, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("upgrade to websocket failed: %s\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// new or resume session?
|
|
||||||
|
|
||||||
var session *Session
|
|
||||||
|
|
||||||
_, msg, err := wsConn.ReadMessage()
|
|
||||||
if err != nil {
|
|
||||||
wsConn.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
parts := bytes.SplitN(msg, []byte("|"), 2)
|
|
||||||
switch string(parts[0]) {
|
|
||||||
case "start":
|
|
||||||
session = NewSession(wsConn)
|
|
||||||
case "resume":
|
|
||||||
if len(parts) > 1 {
|
|
||||||
session, err = ResumeSession(string(parts[1]), wsConn)
|
|
||||||
if err != nil {
|
|
||||||
handleError(session, fmt.Sprintf("error|500|created new session, restoring failed: %s", err))
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
session = NewSession(wsConn)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
wsConn.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
defer session.Deactivate()
|
|
||||||
|
|
||||||
// start handling requests
|
|
||||||
for {
|
|
||||||
|
|
||||||
_, msg, err := wsConn.ReadMessage()
|
|
||||||
if err != nil {
|
|
||||||
if !websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) {
|
|
||||||
log.Warningf("api: read error: %s", err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Tracef("api: got request %s", string(msg))
|
|
||||||
|
|
||||||
splitParams := bytes.SplitN(msg, []byte("|"), 3)
|
|
||||||
|
|
||||||
if len(splitParams) < 2 {
|
|
||||||
handleError(session, "error|400|too few params")
|
|
||||||
}
|
|
||||||
|
|
||||||
action, key := string(splitParams[0]), string(splitParams[1])
|
|
||||||
|
|
||||||
// if len(splitParams) > 2 {
|
|
||||||
// json := splitParams[2]
|
|
||||||
// log.Infof("JSON: %q", json)
|
|
||||||
// }
|
|
||||||
|
|
||||||
switch action {
|
|
||||||
case "get":
|
|
||||||
Get(session, key)
|
|
||||||
case "subscribe":
|
|
||||||
Subscribe(session, key)
|
|
||||||
case "unsubscribe":
|
|
||||||
Unsubscribe(session, key)
|
|
||||||
case "create":
|
|
||||||
if len(splitParams) < 3 {
|
|
||||||
handleError(session, "error|400|invalid action: cannot create without data")
|
|
||||||
}
|
|
||||||
Save(session, key, true, splitParams[2])
|
|
||||||
case "update":
|
|
||||||
if len(splitParams) < 3 {
|
|
||||||
handleError(session, "error|400|invalid action: cannot update without data")
|
|
||||||
}
|
|
||||||
Save(session, key, false, splitParams[2])
|
|
||||||
case "delete":
|
|
||||||
Delete(session, key)
|
|
||||||
default:
|
|
||||||
handleError(session, "error|400|invalid action: "+action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleError(session *Session, message string) {
|
|
||||||
log.Warningf("api: " + message)
|
|
||||||
toSend := []byte(message)
|
|
||||||
session.send <- toSend
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Safing/safing-core/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Logger(inner http.Handler, name string) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
start := time.Now()
|
|
||||||
|
|
||||||
inner.ServeHTTP(w, r)
|
|
||||||
|
|
||||||
log.Infof(
|
|
||||||
"%s\t%s\t%s\t%s",
|
|
||||||
r.Method,
|
|
||||||
r.RequestURI,
|
|
||||||
name,
|
|
||||||
time.Since(start),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewRouter() *mux.Router {
|
|
||||||
router := mux.NewRouter().StrictSlash(true)
|
|
||||||
|
|
||||||
for _, route := range routes {
|
|
||||||
var handler http.Handler
|
|
||||||
|
|
||||||
handler = route.Handler
|
|
||||||
handler = Logger(handler, route.Name)
|
|
||||||
|
|
||||||
router.
|
|
||||||
Methods(route.Method).
|
|
||||||
PathPrefix(route.Path).
|
|
||||||
Name(route.Name).
|
|
||||||
Handler(handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
return router
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Route struct {
|
|
||||||
Name string
|
|
||||||
Method string
|
|
||||||
Path string
|
|
||||||
Handler http.Handler
|
|
||||||
}
|
|
||||||
|
|
||||||
type Routes []Route
|
|
||||||
|
|
||||||
var routes = Routes{
|
|
||||||
Route{
|
|
||||||
"Index",
|
|
||||||
"GET",
|
|
||||||
"/test",
|
|
||||||
http.StripPrefix("/test", http.FileServer(http.Dir("api/test"))),
|
|
||||||
},
|
|
||||||
Route{
|
|
||||||
"Websockets",
|
|
||||||
"GET",
|
|
||||||
"/api/v1",
|
|
||||||
http.HandlerFunc(apiVersionOneHandler),
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,145 +0,0 @@
|
||||||
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
"github.com/ipfs/go-datastore"
|
|
||||||
uuid "github.com/satori/go.uuid"
|
|
||||||
|
|
||||||
"github.com/Safing/safing-core/database"
|
|
||||||
"github.com/Safing/safing-core/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Session holds data for an api session.
|
|
||||||
type Session struct {
|
|
||||||
database.Base
|
|
||||||
ID string
|
|
||||||
wsConn *websocket.Conn
|
|
||||||
Expires int64
|
|
||||||
Subscriptions []string
|
|
||||||
subscription *database.Subscription
|
|
||||||
send chan []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
var sessionModel *Session // only use this as parameter for database.EnsureModel-like functions
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
database.RegisterModel(sessionModel, func() database.Model { return new(Session) })
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSession creates a new session.
|
|
||||||
func NewSession(wsConn *websocket.Conn) *Session {
|
|
||||||
session := &Session{
|
|
||||||
ID: strings.Replace(uuid.NewV4().String(), "-", "", -1),
|
|
||||||
subscription: database.NewSubscription(),
|
|
||||||
send: make(chan []byte, 1024),
|
|
||||||
}
|
|
||||||
session.wsConn = wsConn
|
|
||||||
session.CreateWithID()
|
|
||||||
log.Tracef("api: created new session: %s", session.ID)
|
|
||||||
toSend := []byte("session|" + session.ID)
|
|
||||||
session.send <- toSend
|
|
||||||
go session.Writer()
|
|
||||||
return session
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResumeSession an existing session.
|
|
||||||
func ResumeSession(id string, wsConn *websocket.Conn) (*Session, error) {
|
|
||||||
session, err := GetSession(id)
|
|
||||||
if err == nil {
|
|
||||||
if session.wsConn != nil {
|
|
||||||
session.wsConn.Close()
|
|
||||||
}
|
|
||||||
session.wsConn = wsConn
|
|
||||||
session.Save()
|
|
||||||
log.Tracef("api: resumed session %s", session.ID)
|
|
||||||
go session.Writer()
|
|
||||||
return session, nil
|
|
||||||
}
|
|
||||||
return NewSession(wsConn), fmt.Errorf("api: failed to restore session %s, creating new", id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deactivate closes down a session, making it ready to be resumed.
|
|
||||||
func (m *Session) Deactivate() {
|
|
||||||
m.wsConn.Close()
|
|
||||||
m.wsConn = nil
|
|
||||||
m.subscription.Destroy()
|
|
||||||
m.subscription = nil
|
|
||||||
m.Save()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscribe subscribes to a database key and saves the new subscription table if the session was already persisted.
|
|
||||||
func (m *Session) Subscribe(subKey string) {
|
|
||||||
m.subscription.Subscribe(subKey)
|
|
||||||
m.Subscriptions = *m.subscription.Subscriptions()
|
|
||||||
if m.GetKey() != nil {
|
|
||||||
m.Save()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unsubscribe unsubscribes from a database key and saves the new subscription table if the session was already persisted.
|
|
||||||
func (m *Session) Unsubscribe(subKey string) {
|
|
||||||
m.subscription.Unsubscribe(subKey)
|
|
||||||
m.Subscriptions = *m.subscription.Subscriptions()
|
|
||||||
if m.GetKey() != nil {
|
|
||||||
m.Save()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateWithID saves Session with the its ID in the default namespace.
|
|
||||||
func (m *Session) CreateWithID() error {
|
|
||||||
m.Expires = time.Now().Add(10 * time.Minute).Unix()
|
|
||||||
return m.CreateObject(&database.ApiSessions, m.ID, m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create saves Session with the provided name in the default namespace.
|
|
||||||
func (m *Session) Create(name string) error {
|
|
||||||
m.Expires = time.Now().Add(10 * time.Minute).Unix()
|
|
||||||
return m.CreateObject(&database.ApiSessions, name, m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateInNamespace saves Session with the provided name in the provided namespace.
|
|
||||||
func (m *Session) CreateInNamespace(namespace *datastore.Key, name string) error {
|
|
||||||
m.Expires = time.Now().Add(10 * time.Minute).Unix()
|
|
||||||
return m.CreateObject(namespace, name, m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save saves Session.
|
|
||||||
func (m *Session) Save() error {
|
|
||||||
m.Expires = time.Now().Add(10 * time.Minute).Unix()
|
|
||||||
return m.SaveObject(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSession fetches Session with the provided name from the default namespace.
|
|
||||||
func GetSession(name string) (*Session, error) {
|
|
||||||
return GetSessionFromNamespace(&database.ApiSessions, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSessionFromNamespace fetches Session with the provided name from the provided namespace.
|
|
||||||
func GetSessionFromNamespace(namespace *datastore.Key, name string) (*Session, error) {
|
|
||||||
object, err := database.GetAndEnsureModel(namespace, name, sessionModel)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
model, ok := object.(*Session)
|
|
||||||
if !ok {
|
|
||||||
return nil, database.NewMismatchError(object, sessionModel)
|
|
||||||
}
|
|
||||||
|
|
||||||
if model.subscription == nil {
|
|
||||||
model.subscription = database.NewSubscription()
|
|
||||||
for _, entry := range model.Subscriptions {
|
|
||||||
model.subscription.Subscribe(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if model.send != nil {
|
|
||||||
model.send = make(chan []byte, 1024)
|
|
||||||
}
|
|
||||||
|
|
||||||
return model, nil
|
|
||||||
}
|
|
|
@ -1,88 +0,0 @@
|
||||||
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/Safing/safing-core/database"
|
|
||||||
"github.com/Safing/safing-core/formats/dsd"
|
|
||||||
"github.com/Safing/safing-core/log"
|
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
"github.com/ipfs/go-datastore"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Writer writes messages to the client.
|
|
||||||
func (m *Session) Writer() {
|
|
||||||
|
|
||||||
wsConn := m.wsConn
|
|
||||||
defer wsConn.Close()
|
|
||||||
sub := m.subscription
|
|
||||||
|
|
||||||
var model database.Model
|
|
||||||
var key *datastore.Key
|
|
||||||
var msg []byte
|
|
||||||
msgCreated := true
|
|
||||||
var err error
|
|
||||||
|
|
||||||
writeLoop:
|
|
||||||
for {
|
|
||||||
|
|
||||||
model = nil
|
|
||||||
key = nil
|
|
||||||
msg = nil
|
|
||||||
|
|
||||||
select {
|
|
||||||
// prioritize direct writes
|
|
||||||
case msg = <-m.send:
|
|
||||||
default:
|
|
||||||
select {
|
|
||||||
case msg = <-m.send:
|
|
||||||
case model = <-sub.Created:
|
|
||||||
msgCreated = true
|
|
||||||
// log.Tracef("api: got new from subscription")
|
|
||||||
case model = <-sub.Updated:
|
|
||||||
msgCreated = false
|
|
||||||
// log.Tracef("api: got update from subscription")
|
|
||||||
case key = <-sub.Deleted:
|
|
||||||
// log.Tracef("api: got delete from subscription")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if model != nil {
|
|
||||||
data, err := database.DumpModel(model, dsd.JSON)
|
|
||||||
if err != nil {
|
|
||||||
log.Warningf("api: could not dump model: %s", err)
|
|
||||||
continue writeLoop
|
|
||||||
}
|
|
||||||
if msgCreated {
|
|
||||||
toSend := append([]byte(fmt.Sprintf("created|%s|", model.GetKey().String())), data...)
|
|
||||||
msg = toSend
|
|
||||||
} else {
|
|
||||||
toSend := append([]byte(fmt.Sprintf("updated|%s|", model.GetKey().String())), data...)
|
|
||||||
msg = toSend
|
|
||||||
}
|
|
||||||
} else if key != nil {
|
|
||||||
toSend := append([]byte(fmt.Sprintf("deleted|%s", key.String())))
|
|
||||||
msg = toSend
|
|
||||||
}
|
|
||||||
|
|
||||||
// exit if we got nil
|
|
||||||
if msg == nil {
|
|
||||||
log.Debugf("api: a sending channel was closed, stopping writer")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// log.Tracef("api: sending %s", string(*msg))
|
|
||||||
err = wsConn.WriteMessage(websocket.BinaryMessage, msg)
|
|
||||||
if err != nil {
|
|
||||||
// if !websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) {
|
|
||||||
log.Warningf("api: write error: %s", err)
|
|
||||||
// }
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue