mirror of
https://github.com/cadmium-im/zirconium-go.git
synced 2024-11-23 10:52:24 +00:00
Complete overhaul, remove all things related to modules
This commit is contained in:
parent
c0ed5c7acf
commit
e6199a1a4f
8
.idea/.gitignore
vendored
Normal file
8
.idea/.gitignore
vendored
Normal file
@ -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/
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/zirconium-go.iml" filepath="$PROJECT_DIR$/.idea/zirconium-go.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
8
.idea/watcherTasks.xml
Normal file
8
.idea/watcherTasks.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectTasksOptions">
|
||||
<enabled-global>
|
||||
<option value="go fmt" />
|
||||
</enabled-global>
|
||||
</component>
|
||||
</project>
|
9
.idea/zirconium-go.iml
Normal file
9
.idea/zirconium-go.iml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -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.
|
10
README.md
10
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.
|
||||
|
@ -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
|
||||
}
|
||||
|
77
core/app_context.go
Normal file
77
core/app_context.go
Normal file
@ -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
|
||||
}
|
@ -5,6 +5,8 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/cadmium-im/zirconium-go/core/models"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
)
|
||||
|
||||
@ -18,7 +20,7 @@ type AuthManager struct {
|
||||
}
|
||||
|
||||
type JWTCustomClaims struct {
|
||||
EntityID string `json:"entityID"`
|
||||
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
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
package core
|
||||
|
||||
// BuiltinPlugins is a list of builtin plugins
|
||||
var BuiltinPlugins = map[string]Module{}
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
11
core/models/auth/auth.go
Normal file
11
core/models/auth/auth.go
Normal file
@ -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"`
|
||||
}
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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"`
|
||||
}
|
||||
|
@ -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
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
21
core/session.go
Normal file
21
core/session.go
Normal file
@ -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()
|
||||
}
|
21
core/user_manager.go
Normal file
21
core/user_manager.go
Normal file
@ -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
|
||||
}
|
@ -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...")
|
||||
}
|
||||
}
|
||||
|
49
core/websocket_server.go
Normal file
49
core/websocket_server.go
Normal file
@ -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)
|
||||
}
|
7
go.mod
7
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
|
||||
)
|
||||
|
151
go.sum
151
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=
|
||||
|
Loading…
Reference in New Issue
Block a user