Skip to content

Commit

Permalink
Merge pull request #20 from singnet/master
Browse files Browse the repository at this point in the history
merge latest
  • Loading branch information
anandrgitnirman committed Jun 28, 2019
2 parents 2d602ae + e0be064 commit b35a1f5
Show file tree
Hide file tree
Showing 11 changed files with 593 additions and 16 deletions.
4 changes: 2 additions & 2 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 8 additions & 3 deletions README.md
@@ -1,6 +1,7 @@
# snet-daemon

[![CircleCI](https://circleci.com/gh/singnet/snet-daemon.svg?style=svg)](https://circleci.com/gh/singnet/snet-daemon)
[![Coverage Status](https://coveralls.io/repos/github/singnet/snet-daemon/badge.svg)](https://coveralls.io/github/singnet/snet-daemon)

SingularityNET Daemon
The daemon is the adapter with which an otherwise SingularityNET-unaware service implementation can be exposed to the SingularityNET platform. It is designed to be deployed as a sidecar proxy alongside the service on a given host.
Expand Down Expand Up @@ -153,7 +154,7 @@ configuration properties can be set using configuration file.
These properties you should usually change before starting daemon for the first
time.
* **blockchain_network_selected** (required; default: "local")
- Name of the network to be used for Daemon possible values are one of (kovan,ropsten,main,local or rinkeby).
Name of the network to be used for Daemon possible values are one of (kovan,ropsten,main,local or rinkeby).
Daemon will automatically read the Registry address associated with this network For local network ( you can also specify the registry address manually),see the blockchain_network_config.json

* **daemon_end_point** (required;) -
Expand Down Expand Up @@ -185,16 +186,20 @@ metadata][service-configuration-metadata].
when passthrough is disabled, daemon echoes requests back as responses; `false`
reserved mostly for testing purposes.

* **passthrough_endpoint** (required iff `service_type` != `executable`) -
* **passthrough_endpoint** (required if `service_type` != `executable`) -
endpoint to which requests should be proxied for handling by service.

* **executable_path** (required iff `service_type` == `executable`) -
* **executable_path** (required if `service_type` == `executable`) -
path to executable to expose as a service.

#### Other properties

This options are less frequently needed.

* **authentication_address** (required if `You need to update Daemon configurations remotely`)
Contains the Authentication address that will be used to validate all requests to update Daemon configuration remotely
through a user interface ( Operator UI)

* **auto_ssl_domain** (optional; default: `""`) -
domain name for which the daemon should automatically acquire SSL certs from [Let's Encrypt](https://letsencrypt.org/).

Expand Down
5 changes: 3 additions & 2 deletions config/config.go
Expand Up @@ -17,7 +17,8 @@ import (
)

const (

//Contains the Authentication address that will be used to validate all requests to update Daemon configuration remotely through a user interface
AuthenticationAddress= "authentication_address"
AutoSSLDomainKey = "auto_ssl_domain"
AutoSSLCacheDirKey = "auto_ssl_cache_dir"
BlockchainEnabledKey = "blockchain_enabled"
Expand Down Expand Up @@ -51,7 +52,7 @@ const (
NotificationServiceEndpoint = "notification_svc_end_point"
ServiceHeartbeatType = "service_heartbeat_type"
//none|grpc|http

//This defaultConfigJson will eventually be replaced by DefaultDaemonConfigurationSchema
defaultConfigJson string = `
{
"auto_ssl_domain": "",
Expand Down
103 changes: 103 additions & 0 deletions config/configuration_schema.go
@@ -0,0 +1,103 @@
package config

import (
"encoding/json"
"github.com/spf13/viper"
"strings"
)

//TO DO, Work in Progress , this defines the complete Schema of the Daemon Configuration
//Defined the schema of a few configurations to give an example, you need to define the schema of a given configuration here to see it on the UI

//Used to map the attribute values to a struct
type ConfigurationDetails struct {
Name string //the key of the attribute becomes the Value of the Name
Mandatory bool `json:"mandatory"`
DefaultValue string `json:"value"`
Description string `json:"description"`
Type string `json:"type"`
Editable bool `json:"editable"`
RestartDaemon bool `json:"restart_daemon"`
Section string `json:"section"`
}


const DefaultDaemonConfigurationSchema = `
{
"registry_address_key": {
"mandatory": true,
"value": "0x4e74fefa82e83e0964f0d9f53c68e03f7298a8b2",
"description": "Ethereum address of the Registry contract instance.This is auto determined if not specified based on the blockchain_network_selected If a value is specified ,it will be used and no attempt will be made to auto determine the registry address",
"type": "address",
"editable": false,
"restart_daemon": true,
"section": "blockchain"
}
,
"ethereum_json_rpc_endpoint": {
"mandatory": true,
"value": "https://kovan.infura.io",
"description": "Endpoint to which daemon sends ethereum JSON-RPC requests; Based on the network selected blockchain_network_selected the end point is auto determined.",
"type": "url",
"editable": true,
"restart_daemon": true,
"section": "blockchain"
},
"blockchain_network_selected": {
"mandatory": true,
"value": "local",
"description": "Name of the network to be used for Daemon possible values are one of (kovan,ropsten,main,local or rinkeby). Daemon will automatically read the Registry address associated with this network For local network ( you can also specify the registry address manually),see the blockchain_network_config.json",
"type": "string",
"editable": true,
"restart_daemon": true,
"section": "blockchain"
},
"passthrough_endpoint": {
"mandatory": true,
"value": "http://127.0.0.1:7003",
"description": "endpoint to which requests should be proxied for handling by service.",
"type": "url",
"editable": true,
"restart_daemon": false,
"section": "general"
}
}`

func isLeafNodeKey(key string) (bool,string) {
if strings.Contains(key,".restart_daemon") {
newKey := strings.Replace(key, ".restart_daemon", "",-1)
return true, newKey
}
return false,""
}

func GetConfigurationSchema() ([]ConfigurationDetails,error) {
allConfigurations := make([]ConfigurationDetails, 0) //CHECK THIS
defaultConfigSchema := viper.New()
if err := ReadConfigFromJsonString(defaultConfigSchema, DefaultDaemonConfigurationSchema);err != nil {
return nil,err
}
for _, key := range defaultConfigSchema.AllKeys() {
//Find out if the given key is the key of a Leaf or not .
if isLeaf,leafKey := isLeafNodeKey(key); isLeaf{
configurationDetailsJSON, _ := ConvertStructToJSON(defaultConfigSchema.Get(leafKey))
configDetails := &ConfigurationDetails{}
configDetails.Name = leafKey
_ = json.Unmarshal(configurationDetailsJSON, configDetails)
allConfigurations = append(allConfigurations, *configDetails)
}

}
return allConfigurations,nil
}

//ConvertStructToJSON converts the passed datastructure to a JSON
func ConvertStructToJSON(payLoad interface{}) ([]byte, error) {
b, err := json.Marshal(&payLoad)
if err != nil {
return nil, err
}
return b, nil
}
42 changes: 42 additions & 0 deletions config/configuration_schema_test.go
@@ -0,0 +1,42 @@
package config

import (
"github.com/stretchr/testify/assert"
"testing"
)

func Test_getLeafNodeKey(t *testing.T) {
type args struct {
key string
}
tests := []struct {
name string
args args
want bool
want1 string
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got1 := isLeafNodeKey(tt.args.key)
if got != tt.want {
t.Errorf("isLeafNodeKey() got = %v, want %v", got, tt.want)
}
if got1 != tt.want1 {
t.Errorf("isLeafNodeKey() got1 = %v, want %v", got1, tt.want1)
}
})
}
}

func TestGetSchemaConfiguration(t *testing.T) {
schemaDetails,err := GetConfigurationSchema()
for _,element := range schemaDetails {
if (element.Name == "blockchain_network_selected") {
assert.Equal(t,element.DefaultValue,"local")
}
}
assert.Nil(t,err)
}

52 changes: 52 additions & 0 deletions configuration_service/broadcast_message.go
@@ -0,0 +1,52 @@
package configuration_service

import (
"sync"
)

type MessageBroadcaster struct {
//Operator UI can trigger changes to the Daemon configuration or request the Daemon to stop/start processing requests will ,
// Hence we need a framework to receive this trigger and broadcast it to all the subscribers.
trigger chan int
quit chan int
subscribers []chan int
//This will be used to make sure , we dont interfere with other threads
mutex sync.Mutex
}


func NewChannelBroadcaster() *MessageBroadcaster {
broadcaster := &MessageBroadcaster{}
broadcaster.trigger = make(chan int,1)
go broadcaster.Publish()
return broadcaster
}


//Create a New Subscriber for this broadcaster message
//Interceptors or health checks can subscribe to this and react accordingly
func (broadcast *MessageBroadcaster) NewSubscriber() chan int {
ch := make(chan int, 1)
broadcast.mutex.Lock()
if broadcast.subscribers == nil {
broadcast.subscribers = make([]chan int,0)
}
broadcast.subscribers = append(broadcast.subscribers, ch)
broadcast.mutex.Unlock()
return ch
}


//Once a message is received, pass it down to all the subscribers
func (broadcast *MessageBroadcaster) Publish() {
for {
//Wait for the message to trigger the broadcast
msg := <- broadcast.trigger
broadcast.mutex.Lock()
for _, subscriber := range broadcast.subscribers {
//Now broad the message to all the subscribers.
subscriber <- msg
}
broadcast.mutex.Unlock()
}
}
29 changes: 29 additions & 0 deletions configuration_service/broadcast_message_test.go
@@ -0,0 +1,29 @@
package configuration_service

import (
"github.com/stretchr/testify/assert"

"testing"
)

func TestNewChannelBroadcaster(t *testing.T) {

}

func TestChannelBroadcaster_NewSubscriber(t *testing.T) {
broadcaster := NewChannelBroadcaster()
assert.NotNil(t,broadcaster)
channel1 := broadcaster.NewSubscriber()
channel2 := broadcaster.NewSubscriber()
assert.NotNil(t,channel1)
assert.NotNil(t,channel2)
//Add a message to trigger
broadcaster.trigger <- 1
msg1 := <- channel1
msg2 := <- channel2
assert.Equal(t,1,msg1)
//Check if all the subscribers received the same message
assert.Equal(t,msg2,msg1)
close(broadcaster.trigger)
}

0 comments on commit b35a1f5

Please sign in to comment.