Skip to content

Commit

Permalink
Merge branch 'feat/pregister-test1-on-users' of https://github.com/TE…
Browse files Browse the repository at this point in the history
…RITORI/gno into feat/pregister-test1-on-users
  • Loading branch information
hthieu1110 committed Sep 21, 2024
2 parents e94f97f + a2c504d commit ea64cde
Show file tree
Hide file tree
Showing 16 changed files with 399 additions and 25 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/fossa.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
uses: coursier/cache-action@v6.4.6

- name: Set up JDK 17
uses: coursier/setup-action@v1.3.5
uses: coursier/setup-action@v1.3.6
with:
jvm: temurin:1.17

Expand Down
66 changes: 59 additions & 7 deletions contribs/gnodev/cmd/gnobro/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"flag"
"fmt"
"io"
"log/slog"
"net"
"net/url"
Expand All @@ -21,7 +22,6 @@ import (
"github.com/charmbracelet/wish"
"github.com/charmbracelet/wish/activeterm"
"github.com/charmbracelet/wish/bubbletea"
"github.com/charmbracelet/wish/logging"
"golang.org/x/sync/errgroup"

"github.com/gnolang/gno/contribs/gnodev/pkg/browser"
Expand All @@ -47,6 +47,7 @@ type broCfg struct {
sshListener string
sshHostKeyPath string
banner bool
jsonlog bool
}

var defaultBroOptions = broCfg{
Expand Down Expand Up @@ -152,6 +153,13 @@ func (c *broCfg) RegisterFlags(fs *flag.FlagSet) {
defaultBroOptions.readonly,
"readonly mode, no commands allowed",
)

fs.BoolVar(
&c.jsonlog,
"jsonlog",
defaultBroOptions.jsonlog,
"display server log as json format",
)
}

func execBrowser(cfg *broCfg, args []string, cio commands.IO) error {
Expand Down Expand Up @@ -277,9 +285,7 @@ func runLocal(ctx context.Context, gnocl *gnoclient.Client, cfg *broCfg, bcfg br

func runServer(ctx context.Context, gnocl *gnoclient.Client, cfg *broCfg, bcfg browser.Config, io commands.IO) error {
// setup logger
charmlogger := charmlog.New(io.Out())
charmlogger.SetLevel(charmlog.DebugLevel)
logger := slog.New(charmlogger)
logger := newLogger(io.Out(), cfg.jsonlog)

teaHandler := func(s ssh.Session) (tea.Model, []tea.ProgramOption) {
shortid := fmt.Sprintf("%.10s", s.Context().SessionID())
Expand Down Expand Up @@ -326,8 +332,8 @@ func runServer(ctx context.Context, gnocl *gnoclient.Client, cfg *broCfg, bcfg b
bubbletea.Middleware(teaHandler),
activeterm.Middleware(), // ensure PTY
ValidatePathCommandMiddleware(bcfg.URLPrefix),
logging.StructuredMiddlewareWithLogger(
charmlogger, charmlog.DebugLevel,
StructuredMiddlewareWithLogger(
ctx, logger, slog.LevelInfo,
),
// XXX: add ip throttler
),
Expand Down Expand Up @@ -358,7 +364,9 @@ func runServer(ctx context.Context, gnocl *gnoclient.Client, cfg *broCfg, bcfg b
return err
}

io.Println("Bye!")
if !cfg.jsonlog {
io.Println("Bye!")
}
return nil
}

Expand Down Expand Up @@ -460,3 +468,47 @@ func ValidatePathCommandMiddleware(pathPrefix string) wish.Middleware {
}
}
}

func StructuredMiddlewareWithLogger(ctx context.Context, logger *slog.Logger, level slog.Level) wish.Middleware {
return func(next ssh.Handler) ssh.Handler {
return func(sess ssh.Session) {
ct := time.Now()
hpk := sess.PublicKey() != nil
pty, _, _ := sess.Pty()
logger.Log(
ctx,
level,
"connect",
"user", sess.User(),
"remote-addr", sess.RemoteAddr().String(),
"public-key", hpk,
"command", sess.Command(),
"term", pty.Term,
"width", pty.Window.Width,
"height", pty.Window.Height,
"client-version", sess.Context().ClientVersion(),
)
next(sess)
logger.Log(
ctx,
level,
"disconnect",
"user", sess.User(),
"remote-addr", sess.RemoteAddr().String(),
"duration", time.Since(ct),
)
}
}
}

func newLogger(out io.Writer, json bool) *slog.Logger {
if json {
return slog.New(slog.NewJSONHandler(out, &slog.HandlerOptions{
Level: slog.LevelDebug,
}))
}

charmlogger := charmlog.New(out)
charmlogger.SetLevel(charmlog.DebugLevel)
return slog.New(charmlogger)
}
25 changes: 25 additions & 0 deletions contribs/gnofaucet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Start a local faucet

## Step1:

Make sure you have started gnoland

../../gno.land/build/gnoland start -lazy

## Step2:

Start the faucet.

./build/gnofaucet serve -chain-id dev -mnemonic "source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast"

By default, the faucet sends out 10,000,000ugnot (10gnot) per request.

## Step3:

Make sure you have started website

../../gno.land/build/gnoweb

Request testing tokens from following URL, Have fun!

http://localhost:8888/faucet
2 changes: 1 addition & 1 deletion docs/reference/gno-js-client/gno-provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ Returns **Promise<string\>**
#### Usage

```ts
await provider.getFileContent('gno.land/r/demo/foo20', 'TotalSupply()')
await provider.getFileContent('gno.land/r/demo/foo20')
/*
foo20.gno
foo20_test.gno
Expand Down
72 changes: 72 additions & 0 deletions examples/gno.land/p/demo/fqname/fqname.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Package fqname provides utilities for handling fully qualified identifiers in
// Gno. A fully qualified identifier typically includes a package path followed
// by a dot (.) and then the name of a variable, function, type, or other
// package-level declaration.
package fqname

import "strings"

// Parse splits a fully qualified identifier into its package path and name
// components. It handles cases with and without slashes in the package path.
//
// pkgpath, name := fqname.Parse("gno.land/p/demo/avl.Tree")
// ufmt.Sprintf("Package: %s, Name: %s\n", id.Package, id.Name)
// // Output: Package: gno.land/p/demo/avl, Name: Tree
func Parse(fqname string) (pkgpath, name string) {
// Find the index of the last slash.
lastSlashIndex := strings.LastIndex(fqname, "/")
if lastSlashIndex == -1 {
// No slash found, handle it as a simple package name with dot notation.
dotIndex := strings.LastIndex(fqname, ".")
if dotIndex == -1 {
return fqname, ""
}
return fqname[:dotIndex], fqname[dotIndex+1:]
}

// Get the part after the last slash.
afterSlash := fqname[lastSlashIndex+1:]

// Check for a dot in the substring after the last slash.
dotIndex := strings.Index(afterSlash, ".")
if dotIndex == -1 {
// No dot found after the last slash
return fqname, ""
}

// Split at the dot to separate the base and the suffix.
base := fqname[:lastSlashIndex+1+dotIndex]
suffix := afterSlash[dotIndex+1:]

return base, suffix
}

// Construct a qualified identifier.
//
// fqName := fqname.Construct("gno.land/r/demo/foo20", "GRC20")
// fmt.Println("Fully Qualified Name:", fqName)
// // Output: gno.land/r/demo/foo20.GRC20
func Construct(pkgpath, name string) string {
// TODO: ensure pkgpath is valid - and as such last part does not contain a dot.
if name == "" {
return pkgpath
}
return pkgpath + "." + name
}

// RenderLink creates a formatted link for a fully qualified identifier.
// If the package path starts with "gno.land", it converts it to a markdown link.
// If the domain is different or missing, it returns the input as is.
func RenderLink(pkgPath, slug string) string {
if strings.HasPrefix(pkgPath, "gno.land") {
pkgLink := strings.TrimPrefix(pkgPath, "gno.land")
if slug != "" {
return "[" + pkgPath + "](" + pkgLink + ")." + slug
}
return "[" + pkgPath + "](" + pkgLink + ")"
}
if slug != "" {
return pkgPath + "." + slug
}
return pkgPath
}
74 changes: 74 additions & 0 deletions examples/gno.land/p/demo/fqname/fqname_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package fqname

import (
"testing"

"gno.land/p/demo/uassert"
)

func TestParse(t *testing.T) {
tests := []struct {
input string
expectedPkgPath string
expectedName string
}{
{"gno.land/p/demo/avl.Tree", "gno.land/p/demo/avl", "Tree"},
{"gno.land/p/demo/avl", "gno.land/p/demo/avl", ""},
{"gno.land/p/demo/avl.Tree.Node", "gno.land/p/demo/avl", "Tree.Node"},
{"gno.land/p/demo/avl/nested.Package.Func", "gno.land/p/demo/avl/nested", "Package.Func"},
{"path/filepath.Split", "path/filepath", "Split"},
{"path.Split", "path", "Split"},
{"path/filepath", "path/filepath", ""},
{"path", "path", ""},
{"", "", ""},
}

for _, tt := range tests {
pkgpath, name := Parse(tt.input)
uassert.Equal(t, tt.expectedPkgPath, pkgpath, "Package path did not match")
uassert.Equal(t, tt.expectedName, name, "Name did not match")
}
}

func TestConstruct(t *testing.T) {
tests := []struct {
pkgpath string
name string
expected string
}{
{"gno.land/r/demo/foo20", "GRC20", "gno.land/r/demo/foo20.GRC20"},
{"gno.land/r/demo/foo20", "", "gno.land/r/demo/foo20"},
{"path", "", "path"},
{"path", "Split", "path.Split"},
{"path/filepath", "", "path/filepath"},
{"path/filepath", "Split", "path/filepath.Split"},
{"", "JustName", ".JustName"},
{"", "", ""},
}

for _, tt := range tests {
result := Construct(tt.pkgpath, tt.name)
uassert.Equal(t, tt.expected, result, "Constructed FQName did not match expected")
}
}

func TestRenderLink(t *testing.T) {
tests := []struct {
pkgPath string
slug string
expected string
}{
{"gno.land/p/demo/avl", "Tree", "[gno.land/p/demo/avl](/p/demo/avl).Tree"},
{"gno.land/p/demo/avl", "", "[gno.land/p/demo/avl](/p/demo/avl)"},
{"github.com/a/b", "C", "github.com/a/b.C"},
{"example.com/pkg", "Func", "example.com/pkg.Func"},
{"gno.land/r/demo/foo20", "GRC20", "[gno.land/r/demo/foo20](/r/demo/foo20).GRC20"},
{"gno.land/r/demo/foo20", "", "[gno.land/r/demo/foo20](/r/demo/foo20)"},
{"", "", ""},
}

for _, tt := range tests {
result := RenderLink(tt.pkgPath, tt.slug)
uassert.Equal(t, tt.expected, result, "Rendered link did not match expected")
}
}
3 changes: 3 additions & 0 deletions examples/gno.land/p/demo/fqname/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module gno.land/p/demo/fqname

require gno.land/p/demo/uassert v0.0.0-latest
81 changes: 81 additions & 0 deletions examples/gno.land/p/moul/printfdebugging/color.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package printfdebugging

// consts copied from https://github.com/fatih/color/blob/main/color.go

// Attribute defines a single SGR Code
type Attribute int

const Escape = "\x1b"

// Base attributes
const (
Reset Attribute = iota
Bold
Faint
Italic
Underline
BlinkSlow
BlinkRapid
ReverseVideo
Concealed
CrossedOut
)

const (
ResetBold Attribute = iota + 22
ResetItalic
ResetUnderline
ResetBlinking
_
ResetReversed
ResetConcealed
ResetCrossedOut
)

// Foreground text colors
const (
FgBlack Attribute = iota + 30
FgRed
FgGreen
FgYellow
FgBlue
FgMagenta
FgCyan
FgWhite
)

// Foreground Hi-Intensity text colors
const (
FgHiBlack Attribute = iota + 90
FgHiRed
FgHiGreen
FgHiYellow
FgHiBlue
FgHiMagenta
FgHiCyan
FgHiWhite
)

// Background text colors
const (
BgBlack Attribute = iota + 40
BgRed
BgGreen
BgYellow
BgBlue
BgMagenta
BgCyan
BgWhite
)

// Background Hi-Intensity text colors
const (
BgHiBlack Attribute = iota + 100
BgHiRed
BgHiGreen
BgHiYellow
BgHiBlue
BgHiMagenta
BgHiCyan
BgHiWhite
)
Loading

0 comments on commit ea64cde

Please sign in to comment.