mirror of
https://github.com/openziti/zrok.git
synced 2024-11-22 16:13:47 +01:00
copyto/pastefrom tweaks + readme (#379)
This commit is contained in:
parent
c43f34083d
commit
567ee6c003
117
sdk/examples/pastebin/README.md
Normal file
117
sdk/examples/pastebin/README.md
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
# "pastebin" SDK Example
|
||||||
|
|
||||||
|
This `pastebin` example is a minimal `zrok` SDK application that implements a wormhole that makes redirecting file contents between multiple `zrok` environments very easy.
|
||||||
|
|
||||||
|
The `pastebin` example is split into two separate commands. The `copyto` command takes a copy buffer from standard input. You can use it like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ echo "this is a pastebin test" | copyto
|
||||||
|
access your pastebin using 'pastefrom b46p9j82z81f'
|
||||||
|
```
|
||||||
|
|
||||||
|
And then using another terminal window, you can access your pastebin data like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pastefrom b46p9j82z81f
|
||||||
|
this is a pastebin test
|
||||||
|
```
|
||||||
|
|
||||||
|
## The `copyto` Implementation
|
||||||
|
|
||||||
|
The `copyto` utility is an illustration of how to implement an application that creates a share and exposes it to the `zrok` network. Let's look at each section of the implementation:
|
||||||
|
|
||||||
|
```go
|
||||||
|
data, err := loadData()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This first block of code is responsible for calling the `loadData` function, which loads the pastebin with data from `os.Stdin`.
|
||||||
|
|
||||||
|
All SDK applications need to load the user's "root" from the `environment` package, like this:
|
||||||
|
|
||||||
|
```go
|
||||||
|
root, err := environment.LoadRoot()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `root` is a structure that contains all of the user's environment detail and allows the SDK application to access the `zrok` service instance and the underlying OpenZiti network.
|
||||||
|
|
||||||
|
Next, `copyto` will create a `zrok` share:
|
||||||
|
|
||||||
|
```go
|
||||||
|
shr, err := sdk.CreateShare(root, &sdk.ShareRequest{
|
||||||
|
BackendMode: sdk.TcpTunnelBackendMode,
|
||||||
|
ShareMode: sdk.PrivateShareMode,
|
||||||
|
Target: "pastebin",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("access your pastebin using 'pastefrom %v'\n", shr.Token)
|
||||||
|
```
|
||||||
|
|
||||||
|
The `sdk.CreateShare` call uses the loaded `environment` root along with the details of the share request (`sdk.ShareRequest`) to create the share that will be used to access the `pastebin`.
|
||||||
|
|
||||||
|
For the `pastebin` application, we're using a `sdk.TcpTunnelBackendMode` backend mode (we're just using a single network connection that implements a reliable byte stream, so TCP works great). Tunnel backends only work with `private` shares as of `zrok` `v0.4`, so we're using `sdk.PrivateShareMode`.
|
||||||
|
|
||||||
|
We'll set the `Target` to be `pastebin`, as that's just metadata describing the application.
|
||||||
|
|
||||||
|
Finally, we emit the share token so the user can access the `pastebin` using the `pastefrom` command.
|
||||||
|
|
||||||
|
Next, we'll use the SDK to create a listener for this share:
|
||||||
|
|
||||||
|
```go
|
||||||
|
listener, err := sdk.NewListener(shr.Token, root)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `sdk.NewListener` establishes a network listener for the newly created share. This listener works just like a `net.Listener`.
|
||||||
|
|
||||||
|
Next, we're going to add a shutdown hook so that `copyto` will delete the share when the application is terminated using `^C`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
c := make(chan os.Signal)
|
||||||
|
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||||
|
go func() {
|
||||||
|
<-c
|
||||||
|
if err := sdk.DeleteShare(root, shr); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
_ = listener.Close()
|
||||||
|
os.Exit(0)
|
||||||
|
}()
|
||||||
|
```
|
||||||
|
|
||||||
|
This anonymous function runs waiting for a signal to exit. When that is received, it runs the `sdk.DeleteShare` function to remove the share that was created. This is how ephemeral shares work for the `zrok share` commands as well.
|
||||||
|
|
||||||
|
And finally, we run in an infinite loop waiting for requests for the `pastebin` data from the network:
|
||||||
|
|
||||||
|
```go
|
||||||
|
for {
|
||||||
|
if conn, err := listener.Accept(); err == nil {
|
||||||
|
go handle(conn, data)
|
||||||
|
} else {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## The "pastefrom" Implementation
|
||||||
|
|
||||||
|
The `pastefrom` application works very similarly to `copyto`. The primary difference is that it "dials" the share through the SDK using `sdk.NewDialer`, which returns a `net.Conn`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
conn, err := sdk.NewDialer(shrToken, root)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
When this `sdk.NewDialer` function returns without an error, a bidirectional `net.Conn` has been established between the `copyto` "server" and the `pastefrom` "client". `pastefrom` then just reads the available data from the `net.Conn` and emits it to `os.Stdout`.
|
@ -1,9 +1,12 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/michaelquigley/pfxlog"
|
||||||
"github.com/openziti/zrok/environment"
|
"github.com/openziti/zrok/environment"
|
||||||
"github.com/openziti/zrok/sdk"
|
"github.com/openziti/zrok/sdk"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
@ -11,21 +14,15 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
const MAX_PASTE_SIZE = 64 * 1024
|
func init() {
|
||||||
|
pfxlog.GlobalInit(logrus.WarnLevel, pfxlog.DefaultOptions())
|
||||||
var data []byte
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
stat, _ := os.Stdin.Stat()
|
data, err := loadData()
|
||||||
if stat.Mode()&os.ModeCharDevice == 0 {
|
|
||||||
var err error
|
|
||||||
data, err = io.ReadAll(os.Stdin)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
panic("usage: 'copyto' is requires input from stdin; pipe your paste buffer into it")
|
|
||||||
}
|
|
||||||
|
|
||||||
root, err := environment.LoadRoot()
|
root, err := environment.LoadRoot()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -41,7 +38,7 @@ func main() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("access your pastebin with: 'pastefrom %v'\n", shr.Token)
|
fmt.Printf("access your pastebin using 'pastefrom %v'\n", shr.Token)
|
||||||
|
|
||||||
listener, err := sdk.NewListener(shr.Token, root)
|
listener, err := sdk.NewListener(shr.Token, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -61,14 +58,27 @@ func main() {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
if conn, err := listener.Accept(); err == nil {
|
if conn, err := listener.Accept(); err == nil {
|
||||||
go handle(conn)
|
go handle(conn, data)
|
||||||
} else {
|
} else {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handle(conn net.Conn) {
|
func loadData() ([]byte, error) {
|
||||||
|
stat, _ := os.Stdin.Stat()
|
||||||
|
if stat.Mode()&os.ModeCharDevice == 0 {
|
||||||
|
data, err := io.ReadAll(os.Stdin)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("'copyto' requires input from stdin; direct your paste buffer into stdin")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handle(conn net.Conn, data []byte) {
|
||||||
_, err := conn.Write(data)
|
_, err := conn.Write(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("error: %v\n", err)
|
fmt.Printf("error: %v\n", err)
|
||||||
|
@ -44,5 +44,5 @@ func main() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(string(buf[:n]))
|
fmt.Printf(string(buf[:n]))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user