mirror of
https://github.com/fiatjaf/nak.git
synced 2024-11-22 08:19:06 -05:00
support multiline stdin on decode, encode and fetch, and improve the helpers.
This commit is contained in:
parent
5722061bf3
commit
714d65312c
70
decode.go
70
decode.go
|
@ -34,43 +34,45 @@ var decode = &cli.Command{
|
||||||
},
|
},
|
||||||
ArgsUsage: "<npub | nprofile | nip05 | nevent | naddr | nsec>",
|
ArgsUsage: "<npub | nprofile | nip05 | nevent | naddr | nsec>",
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
args := c.Args()
|
for input := range getStdinLinesOrFirstArgument(c) {
|
||||||
if args.Len() != 1 {
|
if strings.HasPrefix(input, "nostr:") {
|
||||||
return fmt.Errorf("invalid number of arguments, need just one")
|
input = input[6:]
|
||||||
}
|
|
||||||
input := args.First()
|
|
||||||
if strings.HasPrefix(input, "nostr:") {
|
|
||||||
input = input[6:]
|
|
||||||
}
|
|
||||||
|
|
||||||
var decodeResult DecodeResult
|
|
||||||
if b, err := hex.DecodeString(input); err == nil {
|
|
||||||
if len(b) == 64 {
|
|
||||||
decodeResult.HexResult.PossibleTypes = []string{"sig"}
|
|
||||||
decodeResult.HexResult.Signature = hex.EncodeToString(b)
|
|
||||||
} else if len(b) == 32 {
|
|
||||||
decodeResult.HexResult.PossibleTypes = []string{"pubkey", "private_key", "event_id"}
|
|
||||||
decodeResult.HexResult.ID = hex.EncodeToString(b)
|
|
||||||
decodeResult.HexResult.PrivateKey = hex.EncodeToString(b)
|
|
||||||
decodeResult.HexResult.PublicKey = hex.EncodeToString(b)
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("hex string with invalid number of bytes: %d", len(b))
|
|
||||||
}
|
}
|
||||||
} else if evp := sdk.InputToEventPointer(input); evp != nil {
|
|
||||||
decodeResult = DecodeResult{EventPointer: evp}
|
var decodeResult DecodeResult
|
||||||
} else if pp := sdk.InputToProfile(c.Context, input); pp != nil {
|
if b, err := hex.DecodeString(input); err == nil {
|
||||||
decodeResult = DecodeResult{ProfilePointer: pp}
|
if len(b) == 64 {
|
||||||
} else if prefix, value, err := nip19.Decode(input); err == nil && prefix == "naddr" {
|
decodeResult.HexResult.PossibleTypes = []string{"sig"}
|
||||||
ep := value.(nostr.EntityPointer)
|
decodeResult.HexResult.Signature = hex.EncodeToString(b)
|
||||||
decodeResult = DecodeResult{EntityPointer: &ep}
|
} else if len(b) == 32 {
|
||||||
} else if prefix, value, err := nip19.Decode(input); err == nil && prefix == "nsec" {
|
decodeResult.HexResult.PossibleTypes = []string{"pubkey", "private_key", "event_id"}
|
||||||
decodeResult.PrivateKey.PrivateKey = value.(string)
|
decodeResult.HexResult.ID = hex.EncodeToString(b)
|
||||||
decodeResult.PrivateKey.PublicKey, _ = nostr.GetPublicKey(value.(string))
|
decodeResult.HexResult.PrivateKey = hex.EncodeToString(b)
|
||||||
} else {
|
decodeResult.HexResult.PublicKey = hex.EncodeToString(b)
|
||||||
return fmt.Errorf("couldn't decode input")
|
} else {
|
||||||
|
lineProcessingError(c, "hex string with invalid number of bytes: %d", len(b))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else if evp := sdk.InputToEventPointer(input); evp != nil {
|
||||||
|
decodeResult = DecodeResult{EventPointer: evp}
|
||||||
|
} else if pp := sdk.InputToProfile(c.Context, input); pp != nil {
|
||||||
|
decodeResult = DecodeResult{ProfilePointer: pp}
|
||||||
|
} else if prefix, value, err := nip19.Decode(input); err == nil && prefix == "naddr" {
|
||||||
|
ep := value.(nostr.EntityPointer)
|
||||||
|
decodeResult = DecodeResult{EntityPointer: &ep}
|
||||||
|
} else if prefix, value, err := nip19.Decode(input); err == nil && prefix == "nsec" {
|
||||||
|
decodeResult.PrivateKey.PrivateKey = value.(string)
|
||||||
|
decodeResult.PrivateKey.PublicKey, _ = nostr.GetPublicKey(value.(string))
|
||||||
|
} else {
|
||||||
|
lineProcessingError(c, "couldn't decode input '%s': %s", input, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(decodeResult.JSON())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(decodeResult.JSON())
|
exitIfLineProcessingError(c)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
197
encode.go
197
encode.go
|
@ -28,36 +28,44 @@ var encode = &cli.Command{
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "npub",
|
Name: "npub",
|
||||||
Usage: "encode a hex private key into bech32 'npub' format",
|
Usage: "encode a hex public key into bech32 'npub' format",
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
target := getStdinOrFirstArgument(c)
|
for target := range getStdinLinesOrFirstArgument(c) {
|
||||||
if err := validate32BytesHex(target); err != nil {
|
if err := validate32BytesHex(target); err != nil {
|
||||||
return err
|
lineProcessingError(c, "invalid public key: %s", target, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if npub, err := nip19.EncodePublicKey(target); err == nil {
|
||||||
|
fmt.Println(npub)
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if npub, err := nip19.EncodePublicKey(target); err == nil {
|
exitIfLineProcessingError(c)
|
||||||
fmt.Println(npub)
|
return nil
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "nsec",
|
Name: "nsec",
|
||||||
Usage: "encode a hex private key into bech32 'nsec' format",
|
Usage: "encode a hex private key into bech32 'nsec' format",
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
target := getStdinOrFirstArgument(c)
|
for target := range getStdinLinesOrFirstArgument(c) {
|
||||||
if err := validate32BytesHex(target); err != nil {
|
if err := validate32BytesHex(target); err != nil {
|
||||||
return err
|
lineProcessingError(c, "invalid private key: %s", target, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if npub, err := nip19.EncodePrivateKey(target); err == nil {
|
||||||
|
fmt.Println(npub)
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if npub, err := nip19.EncodePrivateKey(target); err == nil {
|
exitIfLineProcessingError(c)
|
||||||
fmt.Println(npub)
|
return nil
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -71,22 +79,26 @@ var encode = &cli.Command{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
target := getStdinOrFirstArgument(c)
|
for target := range getStdinLinesOrFirstArgument(c) {
|
||||||
if err := validate32BytesHex(target); err != nil {
|
if err := validate32BytesHex(target); err != nil {
|
||||||
return err
|
lineProcessingError(c, "invalid public key: %s", target, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
relays := c.StringSlice("relay")
|
||||||
|
if err := validateRelayURLs(relays); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if npub, err := nip19.EncodeProfile(target, relays); err == nil {
|
||||||
|
fmt.Println(npub)
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
relays := c.StringSlice("relay")
|
exitIfLineProcessingError(c)
|
||||||
if err := validateRelayURLs(relays); err != nil {
|
return nil
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if npub, err := nip19.EncodeProfile(target, relays); err == nil {
|
|
||||||
fmt.Println(npub)
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -104,29 +116,33 @@ var encode = &cli.Command{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
target := getStdinOrFirstArgument(c)
|
for target := range getStdinLinesOrFirstArgument(c) {
|
||||||
if err := validate32BytesHex(target); err != nil {
|
if err := validate32BytesHex(target); err != nil {
|
||||||
return err
|
lineProcessingError(c, "invalid event id: %s", target, err)
|
||||||
}
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
author := c.String("author")
|
author := c.String("author")
|
||||||
if author != "" {
|
if author != "" {
|
||||||
if err := validate32BytesHex(author); err != nil {
|
if err := validate32BytesHex(author); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
relays := c.StringSlice("relay")
|
||||||
|
if err := validateRelayURLs(relays); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if npub, err := nip19.EncodeEvent(target, relays, author); err == nil {
|
||||||
|
fmt.Println(npub)
|
||||||
|
} else {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
relays := c.StringSlice("relay")
|
exitIfLineProcessingError(c)
|
||||||
if err := validateRelayURLs(relays); err != nil {
|
return nil
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if npub, err := nip19.EncodeEvent(target, relays, author); err == nil {
|
|
||||||
fmt.Println(npub)
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -136,7 +152,7 @@ var encode = &cli.Command{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "identifier",
|
Name: "identifier",
|
||||||
Aliases: []string{"d"},
|
Aliases: []string{"d"},
|
||||||
Usage: "the \"d\" tag identifier of this replaceable event",
|
Usage: "the \"d\" tag identifier of this replaceable event -- can also be read from stdin",
|
||||||
Required: true,
|
Required: true,
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
|
@ -158,49 +174,60 @@ var encode = &cli.Command{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
pubkey := c.String("pubkey")
|
for d := range getStdinLinesOrBlank() {
|
||||||
if err := validate32BytesHex(pubkey); err != nil {
|
pubkey := c.String("pubkey")
|
||||||
return err
|
if err := validate32BytesHex(pubkey); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
kind := c.Int("kind")
|
||||||
|
if kind < 30000 || kind >= 40000 {
|
||||||
|
return fmt.Errorf("kind must be between 30000 and 39999, as per NIP-16, got %d", kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
if d == "" {
|
||||||
|
d = c.String("identifier")
|
||||||
|
if d == "" {
|
||||||
|
lineProcessingError(c, "\"d\" tag identifier can't be empty")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
relays := c.StringSlice("relay")
|
||||||
|
if err := validateRelayURLs(relays); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if npub, err := nip19.EncodeEntity(pubkey, kind, d, relays); err == nil {
|
||||||
|
fmt.Println(npub)
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kind := c.Int("kind")
|
exitIfLineProcessingError(c)
|
||||||
if kind < 30000 || kind >= 40000 {
|
return nil
|
||||||
return fmt.Errorf("kind must be between 30000 and 39999, as per NIP-16, got %d", kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
d := c.String("identifier")
|
|
||||||
if d == "" {
|
|
||||||
return fmt.Errorf("\"d\" tag identifier can't be empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
relays := c.StringSlice("relay")
|
|
||||||
if err := validateRelayURLs(relays); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if npub, err := nip19.EncodeEntity(pubkey, kind, d, relays); err == nil {
|
|
||||||
fmt.Println(npub)
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "note",
|
Name: "note",
|
||||||
Usage: "generate note1 event codes (not recommended)",
|
Usage: "generate note1 event codes (not recommended)",
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
target := getStdinOrFirstArgument(c)
|
for target := range getStdinLinesOrFirstArgument(c) {
|
||||||
if err := validate32BytesHex(target); err != nil {
|
if err := validate32BytesHex(target); err != nil {
|
||||||
return err
|
lineProcessingError(c, "invalid event id: %s", target, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if note, err := nip19.EncodeNote(target); err == nil {
|
||||||
|
fmt.Println(note)
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if npub, err := nip19.EncodeNote(target); err == nil {
|
exitIfLineProcessingError(c)
|
||||||
fmt.Println(npub)
|
return nil
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
112
fetch.go
112
fetch.go
|
@ -24,67 +24,71 @@ var fetch = &cli.Command{
|
||||||
},
|
},
|
||||||
ArgsUsage: "[nip19code]",
|
ArgsUsage: "[nip19code]",
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
filter := nostr.Filter{}
|
for code := range getStdinLinesOrFirstArgument(c) {
|
||||||
code := getStdinOrFirstArgument(c)
|
filter := nostr.Filter{}
|
||||||
|
|
||||||
prefix, value, err := nip19.Decode(code)
|
prefix, value, err := nip19.Decode(code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
lineProcessingError(c, "failed to decode: %s", err)
|
||||||
}
|
continue
|
||||||
|
|
||||||
relays := c.StringSlice("relay")
|
|
||||||
if err := validateRelayURLs(relays); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var authorHint string
|
|
||||||
|
|
||||||
switch prefix {
|
|
||||||
case "nevent":
|
|
||||||
v := value.(nostr.EventPointer)
|
|
||||||
filter.IDs = append(filter.IDs, v.ID)
|
|
||||||
if v.Author != "" {
|
|
||||||
authorHint = v.Author
|
|
||||||
}
|
}
|
||||||
relays = v.Relays
|
|
||||||
case "naddr":
|
|
||||||
v := value.(nostr.EntityPointer)
|
|
||||||
filter.Tags = nostr.TagMap{"d": []string{v.Identifier}}
|
|
||||||
filter.Kinds = append(filter.Kinds, v.Kind)
|
|
||||||
filter.Authors = append(filter.Authors, v.PublicKey)
|
|
||||||
authorHint = v.PublicKey
|
|
||||||
relays = v.Relays
|
|
||||||
case "nprofile":
|
|
||||||
v := value.(nostr.ProfilePointer)
|
|
||||||
filter.Authors = append(filter.Authors, v.PublicKey)
|
|
||||||
filter.Kinds = append(filter.Kinds, 0)
|
|
||||||
authorHint = v.PublicKey
|
|
||||||
relays = v.Relays
|
|
||||||
case "npub":
|
|
||||||
v := value.(string)
|
|
||||||
filter.Authors = append(filter.Authors, v)
|
|
||||||
filter.Kinds = append(filter.Kinds, 0)
|
|
||||||
authorHint = v
|
|
||||||
}
|
|
||||||
|
|
||||||
pool := nostr.NewSimplePool(c.Context)
|
relays := c.StringSlice("relay")
|
||||||
if authorHint != "" {
|
if err := validateRelayURLs(relays); err != nil {
|
||||||
relayList := sdk.FetchRelaysForPubkey(c.Context, pool, authorHint,
|
return err
|
||||||
"wss://purplepag.es", "wss://offchain.pub", "wss://public.relaying.io")
|
}
|
||||||
for _, relayListItem := range relayList {
|
var authorHint string
|
||||||
if relayListItem.Outbox {
|
|
||||||
relays = append(relays, relayListItem.URL)
|
switch prefix {
|
||||||
|
case "nevent":
|
||||||
|
v := value.(nostr.EventPointer)
|
||||||
|
filter.IDs = append(filter.IDs, v.ID)
|
||||||
|
if v.Author != "" {
|
||||||
|
authorHint = v.Author
|
||||||
|
}
|
||||||
|
relays = v.Relays
|
||||||
|
case "naddr":
|
||||||
|
v := value.(nostr.EntityPointer)
|
||||||
|
filter.Tags = nostr.TagMap{"d": []string{v.Identifier}}
|
||||||
|
filter.Kinds = append(filter.Kinds, v.Kind)
|
||||||
|
filter.Authors = append(filter.Authors, v.PublicKey)
|
||||||
|
authorHint = v.PublicKey
|
||||||
|
relays = v.Relays
|
||||||
|
case "nprofile":
|
||||||
|
v := value.(nostr.ProfilePointer)
|
||||||
|
filter.Authors = append(filter.Authors, v.PublicKey)
|
||||||
|
filter.Kinds = append(filter.Kinds, 0)
|
||||||
|
authorHint = v.PublicKey
|
||||||
|
relays = v.Relays
|
||||||
|
case "npub":
|
||||||
|
v := value.(string)
|
||||||
|
filter.Authors = append(filter.Authors, v)
|
||||||
|
filter.Kinds = append(filter.Kinds, 0)
|
||||||
|
authorHint = v
|
||||||
|
}
|
||||||
|
|
||||||
|
pool := nostr.NewSimplePool(c.Context)
|
||||||
|
if authorHint != "" {
|
||||||
|
relayList := sdk.FetchRelaysForPubkey(c.Context, pool, authorHint,
|
||||||
|
"wss://purplepag.es", "wss://offchain.pub", "wss://public.relaying.io")
|
||||||
|
for _, relayListItem := range relayList {
|
||||||
|
if relayListItem.Outbox {
|
||||||
|
relays = append(relays, relayListItem.URL)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(relays) == 0 {
|
||||||
|
lineProcessingError(c, "no relay hints found")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for ie := range pool.SubManyEose(c.Context, relays, nostr.Filters{filter}) {
|
||||||
|
fmt.Println(ie.Event)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(relays) == 0 {
|
exitIfLineProcessingError(c)
|
||||||
return fmt.Errorf("no relay hints found")
|
|
||||||
}
|
|
||||||
|
|
||||||
for ie := range pool.SubManyEose(c.Context, relays, nostr.Filters{filter}) {
|
|
||||||
fmt.Println(ie.Event)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
59
helpers.go
59
helpers.go
|
@ -2,10 +2,8 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -18,40 +16,47 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func getStdinLinesOrBlank() chan string {
|
func getStdinLinesOrBlank() chan string {
|
||||||
ch := make(chan string)
|
multi := make(chan string)
|
||||||
go func() {
|
if hasStdinLines := writeStdinLinesOrNothing(multi); !hasStdinLines {
|
||||||
if stat, _ := os.Stdin.Stat(); stat.Mode()&os.ModeCharDevice == 0 {
|
single := make(chan string, 1)
|
||||||
// piped
|
single <- ""
|
||||||
scanner := bufio.NewScanner(os.Stdin)
|
close(single)
|
||||||
for scanner.Scan() {
|
return single
|
||||||
ch <- scanner.Text()
|
} else {
|
||||||
}
|
return multi
|
||||||
} else {
|
}
|
||||||
// not piped
|
|
||||||
ch <- ""
|
|
||||||
}
|
|
||||||
close(ch)
|
|
||||||
}()
|
|
||||||
return ch
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getStdinOrFirstArgument(c *cli.Context) string {
|
func getStdinLinesOrFirstArgument(c *cli.Context) chan string {
|
||||||
// try the first argument
|
// try the first argument
|
||||||
target := c.Args().First()
|
target := c.Args().First()
|
||||||
if target != "" {
|
if target != "" {
|
||||||
return target
|
single := make(chan string, 1)
|
||||||
|
single <- target
|
||||||
|
return single
|
||||||
}
|
}
|
||||||
|
|
||||||
// try the stdin
|
// try the stdin
|
||||||
stat, _ := os.Stdin.Stat()
|
multi := make(chan string)
|
||||||
if (stat.Mode() & os.ModeCharDevice) == 0 {
|
writeStdinLinesOrNothing(multi)
|
||||||
read := bytes.NewBuffer(make([]byte, 0, 1000))
|
return multi
|
||||||
_, err := io.Copy(read, os.Stdin)
|
}
|
||||||
if err == nil {
|
|
||||||
return strings.TrimSpace(read.String())
|
func writeStdinLinesOrNothing(ch chan string) (hasStdinLines bool) {
|
||||||
}
|
if stat, _ := os.Stdin.Stat(); stat.Mode()&os.ModeCharDevice == 0 {
|
||||||
|
// piped
|
||||||
|
go func() {
|
||||||
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
|
for scanner.Scan() {
|
||||||
|
ch <- strings.TrimSpace(scanner.Text())
|
||||||
|
}
|
||||||
|
close(ch)
|
||||||
|
}()
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
// not piped
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateRelayURLs(wsurls []string) error {
|
func validateRelayURLs(wsurls []string) error {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user