Skip to content

Commit

Permalink
Structure flag parsing
Browse files Browse the repository at this point in the history
Make a flagset for each discrete config. This
makes ordering feasible. Notably Profile() is
treadted properly.

This way it's possible to avoid race conditions.
  • Loading branch information
bahner committed Apr 7, 2024
1 parent 1c44e91 commit 8b35983
Show file tree
Hide file tree
Showing 25 changed files with 540 additions and 335 deletions.
23 changes: 20 additions & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,27 @@
},
"args": [
"--generate",
"--nick",
"--profile",
"FUBAR",
"--publish",
"--force",
"--nick",
"FUBAR"
]
},
{
"name": "go-ma-actor-relay generate",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/cmd/relay/",
"console": "integratedTerminal",
"env": {
"GOLOG_FILE": "debug.log",
"GOLOG_LOG_LEVEL": "debug",
"GOLOG_STDOUT": "false",
"GOLOG_OUTPUT": "file"
},
"args": [
"--generate",
]
}
]
Expand Down
4 changes: 2 additions & 2 deletions cmd/node/actors.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ func getOrCreateActor(id string) (*actor.Actor, error) {
}

// Assuming entity.NewFromKeyset returns *actor.Actor
a, err := actor.NewFromKeyset(k)
a, err := actor.New(k)
if err != nil {
return nil, fmt.Errorf("failed to create entity: %w", err)
}

a.Entity.Doc, err = a.CreateEntityDocument(a.Entity.DID.Id)
a.Entity.Doc, err = doc.NewFromKeyset(a.Keyset)
if err != nil {
return nil, fmt.Errorf("failed to create DID Document: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/pong/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func main() {
go handleMessageEvents(ctx, a)
fmt.Println("Started event handlers.")

actor.HelloWorld(ctx, a)
a.HelloWorld(ctx)
fmt.Println("Sent hello world.")

// WEB
Expand Down
3 changes: 1 addition & 2 deletions cmd/relay/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"os"

"github.com/bahner/go-ma-actor/config"
"github.com/spf13/pflag"
"gopkg.in/yaml.v2"
)

Expand All @@ -18,8 +17,8 @@ type RelayConfig struct {

func initConfig(defaultProfileName string) RelayConfig {

pflag.Parse()
config.SetDefaultProfileName(defaultProfileName)
config.ParseCommonFlags(true)
config.Init()

c := RelayConfig{
Expand Down
3 changes: 1 addition & 2 deletions cmd/robot/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"log"

"github.com/bahner/go-ma-actor/entity/actor"
"github.com/bahner/go-ma-actor/ui/web"

"github.com/bahner/go-ma-actor/p2p"
Expand Down Expand Up @@ -34,7 +33,7 @@ func main() {
log.Fatal(err)
}

actor.HelloWorld(ctx, i.Robot)
i.Robot.HelloWorld(ctx)
// i.Robot.HelloWorld(ctx, a)

fmt.Println("Press Ctrl-C to stop.")
Expand Down
130 changes: 119 additions & 11 deletions config/actor.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
package config

// This file contains the configuration for the actor package.
// It also somewhat strangeky initialises the identoty and generates a new one if needed.
// This is because it's so low level and the identity is needed for the keyset.

import (
"context"
"fmt"
"os"
"sync"

"github.com/bahner/go-ma/api"
"github.com/spf13/pflag"
"github.com/spf13/viper"

"github.com/bahner/go-ma/did/doc"
"github.com/bahner/go-ma/key/set"
log "github.com/sirupsen/logrus"
)
Expand All @@ -17,25 +25,49 @@ const (
)

var (
keyset set.Keyset
actorKeyset set.Keyset
ErrEmptyIdentity = fmt.Errorf("identity is empty")
ErrFakeIdentity = fmt.Errorf("your identity is fake. You need to define actorKeyset or generate a new one")
ErrEmptyNick = fmt.Errorf("nick is empty")
ActorFlags pflag.FlagSet
actorOnce sync.Once
)

// Initialise command line flags for the actor package
// The actor is optional for some commands, but required for others.
func ActorFlags() {
// exitOnHelp means that this function is the last called when help is needed.
// and the program should exit.
func ParseActorFlags(exitOnHelp bool) {

InitCommon()
InitLog()
InitDB()
InitP2P()
InitHTTP()

actorOnce.Do(func() {

pflag.StringP("nick", "n", "", "Nickname to use in character creation")
pflag.StringP("location", "l", defaultLocation, "DID of the location to visit")
ActorFlags.StringP("nick", "n", "", "Nickname to use in character creation")
ActorFlags.StringP("location", "l", defaultLocation, "DID of the location to visit")

viper.BindPFlag("actor.nick", pflag.Lookup("nick"))
viper.BindPFlag("actor.location", pflag.Lookup("location"))
viper.BindPFlag("actor.nick", ActorFlags.Lookup("nick"))
viper.BindPFlag("actor.location", ActorFlags.Lookup("location"))

viper.SetDefault("actor.location", defaultLocation)
viper.SetDefault("actor.nick", defaultNick())
viper.SetDefault("actor.location", defaultLocation)
viper.SetDefault("actor.nick", defaultNick())

if HelpNeeded() {
fmt.Println("Actor Flags:")
ActorFlags.PrintDefaults()

if exitOnHelp {
os.Exit(0)
}

} else {
ActorFlags.Parse(os.Args[1:])
}
})
}

type ActorConfig struct {
Expand All @@ -44,24 +76,77 @@ type ActorConfig struct {
Location string `yaml:"location"`
}

// Cofig for actor. Remember to parse the flags first.
// Config for actor. Remember to parse the flags first.
// Eg. ActorFlags()
func Actor() ActorConfig {

// Fetch the identity from the config or generate one
identity, err := actorIdentity()
if err != nil {
panic(err)
}

// Unpack the keyset from the identity
initActorKeyset(identity)

// If we are generating a new identity we should publish it
if GenerateFlag() {
renameIPNSKey(actorKeyset.DID.Fragment)
publishIdentityFromKeyset(actorKeyset)
}

return ActorConfig{
Identity: identity,
Nick: ActorNick(),
Location: ActorLocation(),
}
}

func renameIPNSKey(name string) error {

keyExists := ipnsKeyExists(name)

if !keyExists {
return nil
}

// If the key exists and the force flag is not set, return an error
if !ForceFlag() {
return fmt.Errorf("config.renameIPNSKey: force flag not set")
}

ctx := context.Background()
ipfsAPI := api.GetIPFSAPI()

backupName := name + "~"
_, _, err := ipfsAPI.Key().Rename(ctx, name, backupName)

log.Infof("Renamed existing IPNS key: %s to %s", name, backupName)

return err
}

func ipnsKeyExists(name string) bool {

ctx := context.Background()

ipfsAPI := api.GetIPFSAPI()

keys, err := ipfsAPI.Key().List(ctx)
if err != nil {
log.Errorf("config.ipnsKeyExists: %v", err)
return false
}

for _, key := range keys {
if key.Name() == name {
return true
}
}

return false
}

// Fetches the actor nick from the config or the command line
// NB! This is a little more complex than the other config functions, as it
// needs to fetch the nick from the command line if it's not in the config.
Expand All @@ -75,7 +160,7 @@ func ActorLocation() string {
}

func ActorKeyset() set.Keyset {
return keyset
return actorKeyset
}

func actorIdentity() (string, error) {
Expand Down Expand Up @@ -108,7 +193,7 @@ func initActorKeyset(keyset_string string) {
os.Exit(64) // EX_USAGE
}

keyset, err = set.Unpack(keyset_string)
actorKeyset, err = set.Unpack(keyset_string)
if err != nil {
log.Errorf("config.initActor: %v", err)
os.Exit(70) // EX_SOFTWARE
Expand All @@ -132,3 +217,26 @@ func generateKeysetString(nick string) (string, error) {

return pks, nil
}

func publishIdentityFromKeyset(k set.Keyset) error {

d, err := doc.NewFromKeyset(k)
if err != nil {
return fmt.Errorf("config.publishIdentityFromKeyset: failed to create DOC: %w", err)
}

assertionMethod, err := d.GetAssertionMethod()
if err != nil {
return fmt.Errorf("config.publishIdentityFromKeyset: %w", err)
}
d.Sign(k.SigningKey, assertionMethod)

_, err = d.Publish()
if err != nil {
return fmt.Errorf("config.publishIdentityFromKeyset: %w", err)

}
log.Debugf("Published identity: %s", d.ID)

return nil
}
Loading

0 comments on commit 8b35983

Please sign in to comment.