diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..73f69e0
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..c883d49
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/watcherTasks.xml b/.idea/watcherTasks.xml
new file mode 100644
index 0000000..4aabca4
--- /dev/null
+++ b/.idea/watcherTasks.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/zirconium-go.iml b/.idea/zirconium-go.iml
new file mode 100644
index 0000000..5e764c4
--- /dev/null
+++ b/.idea/zirconium-go.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..a0ed704
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 ChronosX88
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/README.md b/README.md
index 8675d44..d330b60 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,11 @@
# Zirconium
-**Zirconium** is a Cadmium protocol server experimental implementation
+Zirconium is experimental serverside implementation of Cadmium protocol in Go.
+
+## Contributing
+
+Feel free to open PRs. If you found the bug, please let us know at our [bug tracker](https://github.com/cadmium-im/zirconium-go/issues).
+
+## License
+
+This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
diff --git a/cmd/zr/main.go b/cmd/zr/main.go
index 56290e7..083c5c3 100644
--- a/cmd/zr/main.go
+++ b/cmd/zr/main.go
@@ -5,34 +5,22 @@ import (
"flag"
"fmt"
"io/ioutil"
- "log"
- "net/http"
"os"
- core "github.com/ChronosX88/zirconium/core"
+ "github.com/cadmium-im/zirconium-go/core"
"github.com/google/logger"
- "github.com/gorilla/mux"
- "github.com/gorilla/websocket"
"github.com/pelletier/go-toml"
)
-var connectionHandler = core.NewConnectionHandler()
-var upgrader = websocket.Upgrader{
- CheckOrigin: func(r *http.Request) bool {
- return true
- },
-}
-
func main() {
-
- var cfg core.ServerConfig
+ var cfg core.Config
var configPath string
var generateConfig bool
flag.StringVar(&configPath, "config", "", "Path to config")
flag.BoolVar(&generateConfig, "gen_config", false, "Generate the config")
flag.Parse()
if generateConfig == true {
- sampleConfig := &core.ServerConfig{}
+ sampleConfig := &core.Config{}
val, err := toml.Marshal(sampleConfig)
if err != nil {
logger.Errorf("Failed to generate config: %s", err.Error())
@@ -61,30 +49,14 @@ func main() {
os.Exit(1)
}
- core.InitializeContext(cfg.ServerDomain, cfg.PluginsDirPath, cfg.EnabledPlugins)
- router := mux.NewRouter()
- router.HandleFunc("/", func(response http.ResponseWriter, request *http.Request) {
- response.Write([]byte("Zirconium server is up and running!"))
- }).Methods("GET")
- router.HandleFunc("/ws", wsHandler)
-
+ ac := core.NewAppContext(&cfg)
logger.Info("Zirconium successfully started!")
- logger.Fatal(http.ListenAndServe(":8844", router))
+ logger.Fatal(ac.Run())
}
-func wsHandler(w http.ResponseWriter, r *http.Request) {
- ws, err := upgrader.Upgrade(w, r, nil)
- if err != nil {
- log.Fatal(err)
- }
- connectionHandler.HandleNewConnection(ws)
-}
-
-func validateConfig(config *core.ServerConfig) error {
- if config.ServerDomain == "" {
- return errors.New("server domain isn't specified")
- } else if config.PluginsDirPath == "" {
- return errors.New("plugin directory path isn't specified")
+func validateConfig(config *core.Config) error {
+ if config.ServerID == "" {
+ return errors.New("server id isn't specified")
}
return nil
}
diff --git a/core/app_context.go b/core/app_context.go
new file mode 100644
index 0000000..3b9bfda
--- /dev/null
+++ b/core/app_context.go
@@ -0,0 +1,77 @@
+package core
+
+import (
+ "context"
+ "fmt"
+ "github.com/google/logger"
+ "go.mongodb.org/mongo-driver/mongo"
+ "go.mongodb.org/mongo-driver/mongo/options"
+ "go.mongodb.org/mongo-driver/mongo/readpref"
+)
+
+type AppContext struct {
+ router *Router
+ authManager *AuthManager
+ connectionHandler *ConnectionHandler
+ websocketServer *WebsocketServer
+ cfg *Config
+ database *mongo.Database
+ userManager *UserManager
+}
+
+func NewAppContext(cfg *Config) *AppContext {
+ var err error
+ appContext := &AppContext{}
+ appContext.cfg = cfg
+
+ appContext.connectToDatabase()
+
+ router, err := NewRouter(appContext)
+ if err != nil {
+ logger.Fatalf("Unable to initialize router: %s", err.Error())
+ }
+ appContext.router = router
+
+ authManager, err := NewAuthManager()
+ if err != nil {
+ logger.Fatalf("Unable to initialize authentication manager: %s", err.Error())
+ }
+ appContext.authManager = authManager
+
+ um := NewUserManager(appContext.database)
+ appContext.userManager = um
+
+ connHandler := NewConnectionHandler(router)
+ appContext.connectionHandler = connHandler
+
+ wss := NewWebsocketServer(cfg, connHandler)
+ appContext.websocketServer = wss
+
+ return appContext
+}
+
+func (ac *AppContext) connectToDatabase() {
+ ctx := context.TODO()
+ dbUri := fmt.Sprintf("mongodb://%s:%s@%s:%d", ac.cfg.Mongo.User, ac.cfg.Mongo.Password, ac.cfg.Mongo.Host, ac.cfg.Mongo.Port)
+ opts := options.Client().ApplyURI(dbUri)
+ err := opts.Validate()
+ if err != nil {
+ logger.Fatalf("invalid database config: %s", err)
+ }
+ mongoClient, err := mongo.Connect(ctx, opts)
+ if err != nil {
+ logger.Fatalf("cannot connect to mongo database: %s", err)
+ }
+ err = mongoClient.Ping(ctx, readpref.Primary())
+ if err != nil {
+ logger.Fatalf("cannot connect to mongo database: %s", err)
+ }
+
+ db := mongoClient.Database(ac.cfg.Mongo.Database)
+ ac.database = db
+}
+
+func (ac *AppContext) Run() error {
+ // TODO
+ return nil
+}
diff --git a/core/auth_manager.go b/core/auth_manager.go
index 93b2eeb..54e576b 100644
--- a/core/auth_manager.go
+++ b/core/auth_manager.go
@@ -5,6 +5,8 @@ import (
"fmt"
"time"
+ "github.com/cadmium-im/zirconium-go/core/models"
+
"github.com/dgrijalva/jwt-go"
)
@@ -18,8 +20,8 @@ type AuthManager struct {
}
type JWTCustomClaims struct {
- EntityID string `json:"entityID"`
- DeviceID string `json:"deviceID"`
+ EntityID []*models.EntityID `json:"entityID"`
+ DeviceID string `json:"deviceID"`
jwt.StandardClaims
}
@@ -33,11 +35,12 @@ func NewAuthManager() (*AuthManager, error) {
return am, nil
}
-func (am *AuthManager) CreateNewToken(entityID, deviceID string, tokenExpireTimeDuration time.Duration) (string, error) {
+func (am *AuthManager) CreateNewToken(entityID *models.EntityID, deviceID string, tokenExpireTimeDuration time.Duration) (string, error) {
timeNow := time.Now()
expiringTime := timeNow.Add(tokenExpireTimeDuration)
+
claims := JWTCustomClaims{
- entityID,
+ []*models.EntityID{entityID},
deviceID,
jwt.StandardClaims{
ExpiresAt: time.Date(
@@ -61,19 +64,23 @@ func (am *AuthManager) CreateNewToken(entityID, deviceID string, tokenExpireTime
return tokenString, nil
}
-func (am *AuthManager) ValidateToken(tokenString string) (bool, string, string, error) {
+func (am *AuthManager) ValidateToken(tokenString string) (*JWTCustomClaims, error) {
token, err := jwt.ParseWithClaims(tokenString, &JWTCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
// Don't forget to validate the alg is what you expect:
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
- return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
+ return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
return []byte(am.signingKey), nil
})
- if claims, ok := token.Claims.(*JWTCustomClaims); ok && token.Valid {
- return true, claims.EntityID, claims.DeviceID, nil
+ if err != nil {
+ return nil, err
}
- return false, "", "", err
+
+ if claims, ok := token.Claims.(*JWTCustomClaims); ok && token.Valid {
+ return claims, nil
+ }
+ return nil, err
}
diff --git a/core/builtin_plugins.go b/core/builtin_plugins.go
deleted file mode 100644
index e389a48..0000000
--- a/core/builtin_plugins.go
+++ /dev/null
@@ -1,4 +0,0 @@
-package core
-
-// BuiltinPlugins is a list of builtin plugins
-var BuiltinPlugins = map[string]Module{}
diff --git a/core/config.go b/core/config.go
index 43d11c3..d1f49c8 100644
--- a/core/config.go
+++ b/core/config.go
@@ -1,12 +1,18 @@
package core
-type ServerConfig struct {
- // A list of enabled plugins (or extensions) in server
- EnabledPlugins []string `toml:"enabledPlugins" comment:"A list of enabled plugins (or extensions) in server"`
-
- // Server domain name (e.g. example.com)
- ServerDomain string `toml:"serverDomain" comment:"Server domain name (e.g. example.com)"`
-
- // Path to directory with plugin executables
- PluginsDirPath string `toml:"pluginsDirPath" comment:"Path to directory with plugin executables"`
+type Config struct {
+ ServerDomains []string `comment:"Server domain names (e.g. example.com)"`
+ ServerID string
+ Websocket struct {
+ Host string
+ Port int
+ Endpoint string
+ }
+ Mongo struct {
+ Host string
+ Port int
+ User string
+ Password string
+ Database string
+ }
}
diff --git a/core/connection_handler.go b/core/connection_handler.go
index c438a43..04a6bd8 100644
--- a/core/connection_handler.go
+++ b/core/connection_handler.go
@@ -1,26 +1,28 @@
package core
import (
- "github.com/ChronosX88/zirconium/core/models"
+ "github.com/cadmium-im/zirconium-go/core/models"
"github.com/google/logger"
"github.com/google/uuid"
"github.com/gorilla/websocket"
)
type ConnectionHandler struct {
- connections map[string]*OriginC2S
+ router *Router
+ connections map[string]*Session
}
-func NewConnectionHandler() *ConnectionHandler {
+func NewConnectionHandler(r *Router) *ConnectionHandler {
return &ConnectionHandler{
- connections: make(map[string]*OriginC2S),
+ router: r,
+ connections: make(map[string]*Session),
}
}
func (ch *ConnectionHandler) HandleNewConnection(wsocket *websocket.Conn) {
- uuid, _ := uuid.NewRandom()
- uuidStr := uuid.String()
- o := &OriginC2S{
+ randomUUID, _ := uuid.NewRandom()
+ uuidStr := randomUUID.String()
+ o := &Session{
wsConn: wsocket,
connID: uuidStr,
}
@@ -31,11 +33,11 @@ func (ch *ConnectionHandler) HandleNewConnection(wsocket *websocket.Conn) {
err := o.wsConn.ReadJSON(&msg)
if err != nil {
delete(ch.connections, o.connID)
- o.wsConn.Close()
+ _ = o.wsConn.Close()
logger.Infof("Connection %s was closed. (Reason: %s)", o.connID, err.Error())
break
}
- router.RouteMessage(o, msg)
+ ch.router.RouteMessage(o, msg)
}
}()
logger.Infof("Connection %s was created", o.connID)
diff --git a/core/globals.go b/core/globals.go
deleted file mode 100644
index 83fb485..0000000
--- a/core/globals.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package core
-
-import (
- "github.com/google/logger"
-)
-
-var (
- moduleMgr ModuleAPI
- router *Router
- authManager *AuthManager
- serverDomain string
- pluginManager *PluginManager
-)
-
-func InitializeContext(sDomain string, pluginsDirPath string, enabledPlugins []string) {
- var err error
- moduleMgr, err = NewModuleManager()
- if err != nil {
- logger.Fatalf("Unable to initialize module manager: %s", err.Error())
- }
-
- router, err = NewRouter()
- if err != nil {
- logger.Fatalf("Unable to initialize router: %s", err.Error())
- }
-
- authManager, err = NewAuthManager()
- if err != nil {
- logger.Fatalf("Unable to initialize authentication manager: %s", err.Error())
- }
- serverDomain = sDomain
-
- for _, v := range BuiltinPlugins {
- go v.Initialize(ModuleAPI(moduleMgr)) // Initialize builtin plugins
- }
-
- pluginManager = NewPluginManager()
- for _, v := range enabledPlugins {
- pluginManager.StartPlugin(pluginsDirPath, v, moduleMgr.(*ModuleManager))
- }
-}
diff --git a/core/models/auth/auth.go b/core/models/auth/auth.go
new file mode 100644
index 0000000..2b4a3e3
--- /dev/null
+++ b/core/models/auth/auth.go
@@ -0,0 +1,11 @@
+package auth
+
+type AuthRequest struct {
+ Type string `json:"type"`
+ Fields map[string]interface{} `json:"fields"`
+}
+
+type AuthResponse struct {
+ Token string `json:"token"`
+ DeviceID string `json:"deviceID"`
+}
diff --git a/core/models/base_message.go b/core/models/base_message.go
index d19efd8..b430f02 100644
--- a/core/models/base_message.go
+++ b/core/models/base_message.go
@@ -5,13 +5,12 @@ type BaseMessage struct {
ID string `json:"id"`
MessageType string `json:"type"`
From string `json:"from"`
- To string `json:"to"`
+ To []string `json:"to"`
Ok bool `json:"ok"`
- AuthToken string `json:"authToken"`
Payload map[string]interface{} `json:"payload"`
}
-func NewBaseMessage(id, messageType, from, to string, ok bool, payload map[string]interface{}) BaseMessage {
+func NewBaseMessage(id, messageType, from string, to []string, ok bool, payload map[string]interface{}) BaseMessage {
return BaseMessage{
ID: id,
MessageType: messageType,
diff --git a/core/models/entity_id.go b/core/models/entity_id.go
index 9688f80..49d4288 100644
--- a/core/models/entity_id.go
+++ b/core/models/entity_id.go
@@ -9,8 +9,8 @@ type EntityIDType string
const (
UsernameType EntityIDType = "@"
- RoomAliasType EntityIDType = "#"
- RoomIDType EntityIDType = "!"
+ ChatAliasType EntityIDType = "#"
+ ChatIDType EntityIDType = "!"
)
type EntityID struct {
@@ -19,30 +19,52 @@ type EntityID struct {
ServerPart string
}
-func NewEntityID(entityID string) *EntityID {
- eID := &EntityID{}
- switch EntityIDType(string(entityID[0])) {
+func NewEntityIDFromString(entityID string) (*EntityID, error) {
+ eid := &EntityID{}
+ typ := string(entityID[0])
+ switch EntityIDType(typ) {
case UsernameType:
+ fallthrough
+ case ChatAliasType:
+ fallthrough
+ case ChatIDType:
{
- eID.EntityIDType = UsernameType
- }
- case RoomAliasType:
- {
- eID.EntityIDType = RoomAliasType
- }
- case RoomIDType:
- {
- eID.EntityIDType = RoomIDType
+ eid.EntityIDType = EntityIDType(typ)
}
+ default:
+ return nil, fmt.Errorf("invalid entity id type: %s", typ)
}
+
localAndServerPart := strings.Split(entityID, "@")
if len(localAndServerPart) == 3 {
localAndServerPart = localAndServerPart[1:]
}
- eID.LocalPart = localAndServerPart[0]
- eID.ServerPart = localAndServerPart[1]
+ eid.LocalPart = localAndServerPart[0]
+ eid.ServerPart = localAndServerPart[1]
- return eID
+ return eid, nil
+}
+
+func NewEntityID(typ, localPart, serverPart string) (*EntityID, error) {
+ eid := &EntityID{}
+
+ switch EntityIDType(typ) {
+ case UsernameType:
+ fallthrough
+ case ChatAliasType:
+ fallthrough
+ case ChatIDType:
+ {
+ eid.EntityIDType = EntityIDType(typ)
+ }
+ default:
+ return nil, fmt.Errorf("invalid entity id type: %s", typ)
+ }
+
+ eid.LocalPart = localPart
+ eid.ServerPart = serverPart
+
+ return eid, nil
}
func (eID *EntityID) String() string {
diff --git a/core/models/protocol_error.go b/core/models/protocol_error.go
index 604fd28..9f13a4d 100644
--- a/core/models/protocol_error.go
+++ b/core/models/protocol_error.go
@@ -1,7 +1,7 @@
package models
type ProtocolError struct {
- ErrCode string `json:"errCode"`
- ErrText string `json:"errText"`
- ErrPayload map[string]interface{} `json:"errPayload"`
+ ErrCode string `json:"code"`
+ ErrText string `json:"text"`
+ ErrPayload map[string]interface{} `json:"payload"`
}
diff --git a/core/module.go b/core/module.go
deleted file mode 100644
index a25135c..0000000
--- a/core/module.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package core
-
-const (
- ModuleInterfaceName = "Module"
-)
-
-type Module interface {
- Initialize(moduleAPI ModuleAPI)
- Name() string
- Version() string
-}
-
-type ModuleRef struct {
- F func() Module
-}
-
-type ModuleFunc func() Module
diff --git a/core/module_manager.go b/core/module_manager.go
deleted file mode 100644
index 19f7749..0000000
--- a/core/module_manager.go
+++ /dev/null
@@ -1,100 +0,0 @@
-package core
-
-import (
- "reflect"
- "sync"
- "time"
-
- "github.com/ChronosX88/zirconium/core/models"
-)
-
-type C2SMessageHandler struct {
- HandlerFunc func(origin *OriginC2S, message models.BaseMessage)
- AnonymousAllowed bool
-}
-
-type ModuleManager struct {
- moduleMutex sync.Mutex
- c2sMessageHandlers map[string][]*C2SMessageHandler
- coreEventHandlers map[string][]func(sourceModuleName string, event map[string]interface{})
-}
-
-type ModuleAPI interface {
- Hook(messageType string, anonymousAllowed bool, handlerFunc func(origin *OriginC2S, message models.BaseMessage))
- HookInternalEvent(eventName string, handlerFunc func(sourceModuleName string, event map[string]interface{}))
- Unhook(messageType string, handlerFunc func(origin *OriginC2S, message models.BaseMessage))
- UnhookInternalEvent(eventName string, handlerFunc func(sourceModuleName string, event map[string]interface{}))
- FireEvent(sourceModuleName string, eventName string, eventPayload map[string]interface{})
- GenerateToken(entityID, deviceID string, tokenExpireTimeDuration time.Duration) (string, error)
- GetServerDomain() string
-}
-
-func NewModuleManager() (ModuleAPI, error) {
- var mm = &ModuleManager{
- c2sMessageHandlers: make(map[string][]*C2SMessageHandler),
- coreEventHandlers: make(map[string][]func(sourceModuleName string, event map[string]interface{})),
- }
- return mm, nil
-}
-
-func (mm *ModuleManager) Hook(messageType string, anonymousAllowed bool, handlerFunc func(origin *OriginC2S, message models.BaseMessage)) {
- mm.moduleMutex.Lock()
- mm.c2sMessageHandlers[messageType] = append(mm.c2sMessageHandlers[messageType], &C2SMessageHandler{
- HandlerFunc: handlerFunc,
- AnonymousAllowed: anonymousAllowed,
- })
- mm.moduleMutex.Unlock()
-}
-
-func (mm *ModuleManager) HookInternalEvent(eventName string, handlerFunc func(sourceModuleName string, event map[string]interface{})) {
- mm.moduleMutex.Lock()
- mm.coreEventHandlers[eventName] = append(mm.coreEventHandlers[eventName], handlerFunc)
- mm.moduleMutex.Unlock()
-}
-
-func (mm *ModuleManager) Unhook(messageType string, handlerFunc func(origin *OriginC2S, message models.BaseMessage)) {
- mm.moduleMutex.Lock()
- defer mm.moduleMutex.Unlock()
- var handlers = mm.c2sMessageHandlers[messageType]
- if handlers != nil {
- for i, v := range handlers {
- if reflect.ValueOf(v.HandlerFunc).Pointer() == reflect.ValueOf(handlerFunc).Pointer() {
- handlers[i] = handlers[len(handlers)-1]
- handlers[len(handlers)-1] = nil
- handlers = handlers[:len(handlers)-1]
- mm.c2sMessageHandlers[messageType] = handlers
- break
- }
- }
- }
-}
-
-func (mm *ModuleManager) UnhookInternalEvent(eventName string, handlerFunc func(sourceModuleName string, event map[string]interface{})) {
- mm.moduleMutex.Lock()
- defer mm.moduleMutex.Unlock()
- var handlers = mm.coreEventHandlers[eventName]
- if handlers != nil {
- for i, v := range handlers {
- if reflect.ValueOf(v).Pointer() == reflect.ValueOf(handlerFunc).Pointer() {
- handlers[i] = handlers[len(handlers)-1]
- handlers[len(handlers)-1] = nil
- handlers = handlers[:len(handlers)-1]
- mm.coreEventHandlers[eventName] = handlers
- break
- }
- }
- }
-}
-
-func (mm *ModuleManager) FireEvent(sourceModuleName string, eventName string, eventPayload map[string]interface{}) {
- router.RoutecoreEvent(sourceModuleName, eventName, eventPayload)
-}
-
-func (mm *ModuleManager) GenerateToken(entityID, deviceID string, tokenExpireTimeDuration time.Duration) (string, error) {
- token, err := authManager.CreateNewToken(entityID, deviceID, tokenExpireTimeDuration)
- return token, err
-}
-
-func (mm *ModuleManager) GetServerDomain() string {
- return serverDomain
-}
diff --git a/core/module_rpc_receiver.go b/core/module_rpc_receiver.go
deleted file mode 100644
index 45c183d..0000000
--- a/core/module_rpc_receiver.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package core
-
-import (
- "errors"
-
- "github.com/hashicorp/go-plugin"
-)
-
-type greeterServer struct {
- Broker *plugin.MuxBroker
- Module Module
-}
-
-// Server implmentation of go-plugin.plugin.Plugin.Server
-func (p *ModuleRef) Server(b *plugin.MuxBroker) (interface{}, error) {
- if p.F == nil {
- return nil, errors.New("Greeter interface not implemeted")
- }
- return &greeterServer{Broker: b, Module: p.F()}, nil
-}
-
-// Name calls the plugin implementation to get the name of the plugin
-func (p *greeterServer) Name(nothing interface{}, result *string) error {
- *result = p.Module.Name()
- return nil
-}
-
-// Version calls the plugin implementation to get the version of the plugin
-func (p *greeterServer) Version(nothing interface{}, result *string) error {
- *result = p.Module.Version()
- return nil
-}
-
-// StartTime calls the plugin implementation to initialize plugin
-func (p *greeterServer) Initialize(moduleAPI ModuleAPI, emptyResult interface{}) error {
- p.Module.Initialize(moduleAPI)
- return nil
-}
diff --git a/core/module_rpc_sender.go b/core/module_rpc_sender.go
deleted file mode 100644
index 151e975..0000000
--- a/core/module_rpc_sender.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package core
-
-import (
- "net/rpc"
-
- "github.com/google/logger"
- "github.com/hashicorp/go-plugin"
-)
-
-type moduleClient struct {
- Broker *plugin.MuxBroker
- Client *rpc.Client
-}
-
-// Client implmentation of go-plugin.plugin.Plugin.Client
-func (p *ModuleRef) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
- return &moduleClient{Broker: b, Client: c}, nil
-}
-
-// Name initiates an RPC call to the plugin name
-func (p *moduleClient) Name() string {
- var resp string
- err := p.Client.Call("Plugin.Name", new(interface{}), &resp)
- if err != nil {
- logger.Fatal(err) // FIXME
- }
- return resp
-}
-
-// Version initiates an RPC call to the plugin version
-func (p *moduleClient) Version() string {
- var resp string
- err := p.Client.Call("Plugin.Version", new(interface{}), &resp)
- if err != nil {
- logger.Fatal(err) // FIXME
- }
- return resp
-}
-
-// StartTime initiates an RPC call to the plugin for initializing
-func (p *moduleClient) Initialize(moduleAPI ModuleAPI) {
- var resp interface{}
- err := p.Client.Call("Plugin.Initialize", map[string]interface{}{
- "moduleAPI": moduleAPI,
- }, &resp)
- if err != nil {
- logger.Fatal(err) // FIXME
- }
-}
diff --git a/core/origin_c2s.go b/core/origin_c2s.go
deleted file mode 100644
index 91efebc..0000000
--- a/core/origin_c2s.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package core
-
-import (
- "github.com/ChronosX88/zirconium/core/models"
- "github.com/gorilla/websocket"
-)
-
-type OriginC2S struct {
- wsConn *websocket.Conn
- connID string
- entityID *models.EntityID
- deviceID *string
-}
-
-func (o *OriginC2S) Send(message models.BaseMessage) error {
- return o.wsConn.WriteJSON(message)
-}
diff --git a/core/plugin_manager.go b/core/plugin_manager.go
deleted file mode 100644
index e67a604..0000000
--- a/core/plugin_manager.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package core
-
-import (
- "os"
- "os/exec"
- "path/filepath"
-
- "github.com/google/logger"
- "github.com/hashicorp/go-plugin"
-)
-
-type PluginManager struct{}
-
-func NewPluginManager() *PluginManager {
- return &PluginManager{}
-}
-
-func (p *PluginManager) StartPlugin(pluginsDirPath, pluginFile string, moduleManager ModuleAPI) error {
- pluginsDirectory, _ := filepath.Abs(filepath.Dir(pluginsDirPath))
- pluginFile = filepath.Join(pluginsDirectory, pluginFile)
-
- logger.Info("Starting plugin: %s", pluginFile)
-
- client := plugin.NewClient(&plugin.ClientConfig{
- Cmd: exec.Command(pluginFile),
- Managed: true,
- SyncStdout: os.Stdout,
- SyncStderr: os.Stderr,
-
- HandshakeConfig: HandshakeConfig,
- Plugins: GetPluginMap(nil),
- })
-
- rpcclient, err := client.Client()
-
- if err != nil {
- logger.Errorf("Failed to get RPC Client: %s", err)
- client.Kill()
- return err
- }
-
- // get the interface
- raw, err := rpcclient.Dispense(ModuleInterfaceName)
- if err != nil {
- logger.Errorf("Failed to get interface: %s error: %s", ModuleInterfaceName, err)
- return err
- }
-
- moduleObj := raw.(Module)
-
- go func() {
- moduleObj.Initialize(moduleManager)
- }()
-
- return nil
-}
diff --git a/core/router.go b/core/router.go
index ecfa8dd..021603b 100644
--- a/core/router.go
+++ b/core/router.go
@@ -1,56 +1,43 @@
package core
import (
- "github.com/ChronosX88/zirconium/core/models"
+ "github.com/cadmium-im/zirconium-go/core/models"
"github.com/google/logger"
)
type Router struct {
- moduleManager *ModuleManager
- connections []*OriginC2S
+ appContext *AppContext
+ handlers map[string][]C2SMessageHandler
+ connections []*Session
}
-func NewRouter() (*Router, error) {
- mm, err := NewModuleManager()
- if err != nil {
- return nil, err
- }
+type C2SMessageHandler interface {
+ HandleMessage(s *Session, message models.BaseMessage)
+ IsAuthorizationRequired() bool
+ HandlingType() string
+}
+
+func NewRouter(ctx *AppContext) (*Router, error) {
r := &Router{
- moduleManager: mm.(*ModuleManager),
+ appContext: ctx,
+ handlers: map[string][]C2SMessageHandler{},
}
return r, nil
}
-func (r *Router) RouteMessage(origin *OriginC2S, message models.BaseMessage) {
- handlers := r.moduleManager.c2sMessageHandlers[message.MessageType]
+func (r *Router) RouteMessage(origin *Session, message models.BaseMessage) {
+ handlers := r.handlers[message.MessageType]
if handlers != nil {
for _, v := range handlers {
- if !v.AnonymousAllowed {
- var entityID, deviceID string
- var isValid bool
- var err error
- if message.AuthToken != "" {
- isValid, entityID, deviceID, err = authManager.ValidateToken(message.AuthToken)
- if err != nil || !isValid {
- logger.Warningf("Connection %s isn't authorized", origin.connID)
- msg := PrepareMessageUnauthorized(message)
- origin.Send(msg)
- }
- } else {
+ if v.IsAuthorizationRequired() {
+ if len(origin.entityID) == 0 {
logger.Warningf("Connection %s isn't authorized", origin.connID)
- msg := PrepareMessageUnauthorized(message)
- origin.Send(msg)
- }
-
- if origin.entityID == nil {
- origin.entityID = models.NewEntityID(entityID)
- }
- if origin.deviceID == nil {
- origin.deviceID = &deviceID
+ msg := PrepareMessageUnauthorized(message, r.appContext.cfg.ServerDomains[0]) // fixme: domain
+ _ = origin.Send(msg)
}
}
- go v.HandlerFunc(origin, message)
+ go v.HandleMessage(origin, message)
}
} else {
protocolError := models.ProtocolError{
@@ -58,19 +45,12 @@ func (r *Router) RouteMessage(origin *OriginC2S, message models.BaseMessage) {
ErrText: "Server doesn't implement message type " + message.MessageType,
ErrPayload: make(map[string]interface{}),
}
- errMsg := models.NewBaseMessage(message.ID, message.MessageType, serverDomain, message.From, false, StructToMap(protocolError))
+ errMsg := models.NewBaseMessage(message.ID, message.MessageType, r.appContext.cfg.ServerID, []string{message.From}, false, StructToMap(protocolError))
logger.Infof("Drop message with type %s because server hasn't proper handlers", message.MessageType)
- origin.Send(errMsg)
+ _ = origin.Send(errMsg)
}
}
-func (r *Router) RoutecoreEvent(sourceModuleName string, eventName string, eventPayload map[string]interface{}) {
- handlers := r.moduleManager.coreEventHandlers[eventName]
- if handlers != nil {
- for _, v := range handlers {
- go v(sourceModuleName, eventPayload)
- }
- } else {
- logger.Infof("Drop event %s because server hasn't proper handlers", eventName)
- }
+func (r *Router) RegisterC2SHandler(c C2SMessageHandler) {
+ r.handlers[c.HandlingType()] = append(r.handlers[c.HandlingType()], c)
}
diff --git a/core/session.go b/core/session.go
new file mode 100644
index 0000000..1062955
--- /dev/null
+++ b/core/session.go
@@ -0,0 +1,21 @@
+package core
+
+import (
+ "github.com/cadmium-im/zirconium-go/core/models"
+ "github.com/gorilla/websocket"
+)
+
+type Session struct {
+ wsConn *websocket.Conn
+ connID string
+ entityID []*models.EntityID
+ deviceID *string
+}
+
+func (s *Session) Send(message models.BaseMessage) error {
+ return s.wsConn.WriteJSON(message)
+}
+
+func (s *Session) Close() error {
+ return s.wsConn.Close()
+}
diff --git a/core/user_manager.go b/core/user_manager.go
new file mode 100644
index 0000000..6e38154
--- /dev/null
+++ b/core/user_manager.go
@@ -0,0 +1,21 @@
+package core
+
+import "go.mongodb.org/mongo-driver/mongo"
+
+const (
+ UsersCollectionName = "users"
+)
+
+type UserManager struct {
+ usersCol *mongo.Collection
+}
+
+func NewUserManager(db *mongo.Database) *UserManager {
+ col := db.Collection(UsersCollectionName)
+
+ um := &UserManager{
+ usersCol: col,
+ }
+
+ return um
+}
diff --git a/core/utils.go b/core/utils.go
index 55869ef..57c27af 100644
--- a/core/utils.go
+++ b/core/utils.go
@@ -2,12 +2,9 @@ package core
import (
"crypto/rand"
- "log"
"reflect"
- "github.com/ChronosX88/zirconium/core/models"
- "github.com/google/logger"
- "github.com/hashicorp/go-plugin"
+ "github.com/cadmium-im/zirconium-go/core/models"
)
func GenRandomBytes(size int) (blk []byte, err error) {
@@ -42,58 +39,12 @@ func StructToMap(item interface{}) map[string]interface{} {
return res
}
-func PrepareMessageUnauthorized(msg models.BaseMessage) models.BaseMessage {
+func PrepareMessageUnauthorized(msg models.BaseMessage, serverDomain string) models.BaseMessage {
protocolError := models.ProtocolError{
ErrCode: "unauthorized",
ErrText: "Unauthorized access",
ErrPayload: make(map[string]interface{}),
}
- errMsg := models.NewBaseMessage(msg.ID, msg.MessageType, serverDomain, msg.From, false, StructToMap(protocolError))
+ errMsg := models.NewBaseMessage(msg.ID, msg.MessageType, serverDomain, []string{msg.From}, false, StructToMap(protocolError))
return errMsg
}
-
-var HandshakeConfig = plugin.HandshakeConfig{
- ProtocolVersion: 1,
- MagicCookieKey: "TEST_TEST",
- MagicCookieValue: "qwerty",
-}
-
-type PluginOpts struct {
- Module ModuleFunc
- RunAsPlugin bool
-}
-
-// GetPluginMap returns the plugin map defined Hashicorp go-plugin.
-// The reserved parameter should only be used by the RPC receiver (the plugin).
-// Otherwise, reserved should be nil for the RPC sender (the mainapp).
-func GetPluginMap(reserved *PluginOpts) map[string]plugin.Plugin {
- var moduleObj ModuleRef
-
- if reserved != nil {
- moduleObj.F = reserved.Module
- }
-
- return map[string]plugin.Plugin{
- ModuleInterfaceName: &moduleObj,
- }
-}
-
-func StartPlugin(opts *PluginOpts, quit chan bool) {
- if opts.RunAsPlugin {
- go func() {
- logger.Info("Starting plugin communication...")
-
- plugin.Serve(&plugin.ServeConfig{
- HandshakeConfig: HandshakeConfig,
- Plugins: GetPluginMap(opts),
- })
-
- logger.Info("Exiting plugin communication...")
-
- quit <- true
- logger.Info("Exiting plugin...")
- }()
- } else {
- log.Println("Starting in standalone mode...")
- }
-}
diff --git a/core/websocket_server.go b/core/websocket_server.go
new file mode 100644
index 0000000..6136e40
--- /dev/null
+++ b/core/websocket_server.go
@@ -0,0 +1,49 @@
+package core
+
+import (
+ "fmt"
+ "github.com/google/logger"
+ "github.com/gorilla/mux"
+ "github.com/gorilla/websocket"
+ "net/http"
+)
+
+var wsUpgrader = websocket.Upgrader{
+ CheckOrigin: func(r *http.Request) bool {
+ return true
+ },
+}
+
+type WebsocketServer struct {
+ r *mux.Router
+ connHandler *ConnectionHandler
+ cfg *Config
+}
+
+func NewWebsocketServer(cfg *Config, connHandler *ConnectionHandler) *WebsocketServer {
+ wss := &WebsocketServer{}
+
+ wss.connHandler = connHandler
+ wss.cfg = cfg
+ r := mux.NewRouter()
+ wss.r = r
+ r.HandleFunc("/", func(response http.ResponseWriter, request *http.Request) {
+ _, _ = response.Write([]byte("Zirconium server is up and running!"))
+ }).Methods("GET")
+ r.HandleFunc(cfg.Websocket.Endpoint, func(w http.ResponseWriter, r *http.Request) {
+ ws, err := wsUpgrader.Upgrade(w, r, nil)
+ if err != nil {
+ logger.Errorf(err.Error())
+ return
+ }
+ wss.connHandler.HandleNewConnection(ws)
+ })
+
+ return wss
+}
+
+func (wss *WebsocketServer) Run() error {
+ addr := fmt.Sprintf("%s:%d", wss.cfg.Websocket.Host, wss.cfg.Websocket.Port)
+
+ return http.ListenAndServe(addr, wss.r)
+}
diff --git a/go.mod b/go.mod
index 70eb729..a671728 100644
--- a/go.mod
+++ b/go.mod
@@ -1,13 +1,14 @@
-module github.com/ChronosX88/zirconium
+module github.com/cadmium-im/zirconium-go
go 1.13
require (
+ github.com/BurntSushi/toml v0.3.1
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/google/logger v1.0.1
github.com/google/uuid v1.1.1
github.com/gorilla/mux v1.7.3
github.com/gorilla/websocket v1.4.1
- github.com/hashicorp/go-plugin v1.0.1
- github.com/pelletier/go-toml v1.6.0
+ github.com/pelletier/go-toml v1.7.0
+ go.mongodb.org/mongo-driver v1.5.1
)
diff --git a/go.sum b/go.sum
index 9723e93..ed32168 100644
--- a/go.sum
+++ b/go.sum
@@ -1,14 +1,43 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/aws/aws-sdk-go v1.34.28 h1:sscPpn/Ns3i0F4HPEWAVcwdIRaZZCuL7llJ2/60yPIk=
+github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
+github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
+github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
+github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
+github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
+github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=
+github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
+github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
+github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
+github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=
+github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=
+github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
+github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
+github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
+github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=
+github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
+github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
+github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
+github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
+github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
+github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
+github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
+github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
+github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
+github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
+github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/logger v1.0.1 h1:Jtq7/44yDwUXMaLTYgXFC31zpm6Oku7OI/k4//yVANQ=
github.com/google/logger v1.0.1/go.mod h1:w7O8nrRr0xufejBlQMI83MXqRusvREoJdaAxV+CoAB4=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
@@ -17,37 +46,97 @@ github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd h1:rNuUHR+CvK1IS89MMtcF0EpcVMZtjKfPRp4MEmt/aTs=
-github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
-github.com/hashicorp/go-plugin v1.0.1 h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cRWgnE=
-github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
-github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
-github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
-github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:7GoSOOW2jpsfkntVKaS2rAr1TJqfcxotyaUcuxoZSzg=
-github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
-github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
-github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
-github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=
-github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
+github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
+github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
+github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
+github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
+github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M=
+github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
+github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
+github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
+github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
+github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
+github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
+github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
+github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
+github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
+github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w=
+github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
+github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc=
+github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
+go.mongodb.org/mongo-driver v1.5.1 h1:9nOVLGDfOaZ9R0tBumx/BcuqkbFpyTCU2r/Po7A2azI=
+go.mongodb.org/mongo-driver v1.5.1/go.mod h1:gRXCHX4Jo7J0IJ1oDQyUxF7jfy19UfxniMS4xxMmUqw=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
+golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
+golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2 h1:T5DasATyLQfmbTpfEXx/IOL9vfjzW6up+ZDkmHvIf2s=
+golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/grpc v1.14.0 h1:ArxJuB1NWfPY6r9Gp9gqwplT0Ge7nqv9msgu03lHLmo=
-google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
+golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
-gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/plugins/.gitkeep b/plugins/.gitkeep
deleted file mode 100644
index e69de29..0000000