Added some Documentation and Example of using it with http.Transport
This commit is contained in:
71
README.md
71
README.md
@ -1,4 +1,73 @@
|
||||
goSam
|
||||
=====
|
||||
|
||||
A go library for using the I2P Simple Anonymous Messaging (SAM version 3.0) bridge
|
||||
A go library for using the [I2P](https://geti2p.net/en/) Simple Anonymous Messaging ([SAM version 3.0](https://geti2p.net/en/docs/api/samv3)) bridge
|
||||
|
||||
This is in an **early development stage**. I would love to hear about any issues or ideas for improvement.
|
||||
|
||||
## Installation
|
||||
```
|
||||
go get github.com/cryptix/goSam
|
||||
```
|
||||
|
||||
## Using it for HTTP Transport
|
||||
|
||||
I implemented `Client.Dial` like `net.Dial` so you can use go's library packages like http.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/cryptix/goSam"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// create a default sam client
|
||||
sam, err := goSam.NewDefaultClient()
|
||||
checkErr(err)
|
||||
|
||||
log.Println("Client Created")
|
||||
|
||||
// create a transport that uses SAM to dial TCP Connections
|
||||
tr := &http.Transport{
|
||||
Dial: sam.Dial,
|
||||
}
|
||||
|
||||
// create a client using this transport
|
||||
client := &http.Client{Transport: tr}
|
||||
|
||||
// send a get request
|
||||
resp, err := client.Get("http://stats.i2p/")
|
||||
checkErr(err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
log.Printf("Get returned %+v\n", resp)
|
||||
|
||||
// create a file for the response
|
||||
file, err := os.Create("stats.html")
|
||||
checkErr(err)
|
||||
defer file.Close()
|
||||
|
||||
// copy the response to the file
|
||||
_, err = io.Copy(file, resp.Body)
|
||||
checkErr(err)
|
||||
|
||||
log.Println("Done.")
|
||||
}
|
||||
|
||||
func checkErr(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### TODO
|
||||
|
||||
* Implement `STREAM ACCEPT` and `STREAM FORWARD`
|
||||
* Implement datagrams (Repliable and Anon)
|
@ -7,6 +7,7 @@ import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// A Client represents a single Connection to the SAM bridge
|
||||
type Client struct {
|
||||
SamConn net.Conn
|
||||
verbose bool
|
||||
@ -27,6 +28,7 @@ func NewClient(addr string) (*Client, error) {
|
||||
return c, c.hello()
|
||||
}
|
||||
|
||||
// switches logging on or off. (also passed to new clients inside Dial.)
|
||||
func (c *Client) ToggleVerbose() {
|
||||
c.verbose = !c.verbose
|
||||
}
|
||||
@ -75,6 +77,7 @@ func (c *Client) sendCmd(cmd string) (r *Reply, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Close the underlying socket to SAM
|
||||
func (c *Client) Close() error {
|
||||
return c.SamConn.Close()
|
||||
}
|
||||
|
4
dial.go
4
dial.go
@ -5,7 +5,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// implements the net.Dial function to be used as http.Transport
|
||||
// Implements the net.Dial function can be used for http.Transport
|
||||
func (c *Client) Dial(network, addr string) (net.Conn, error) {
|
||||
portIdx := strings.Index(addr, ":")
|
||||
if portIdx >= 0 {
|
||||
@ -16,7 +16,7 @@ func (c *Client) Dial(network, addr string) (net.Conn, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
id, _, err := c.createStreamSession("")
|
||||
id, _, err := c.CreateStreamSession("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
21
naming.go
21
naming.go
@ -4,27 +4,6 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
ResultOk = "OK" //Operation completed successfully
|
||||
ResultCantReachPeer = "CANT_REACH_PEER" //The peer exists, but cannot be reached
|
||||
ResultDuplicatedId = "DUPLICATED_ID" //If the nickname is already associated with a session :
|
||||
ResultDuplicatedDest = "DUPLICATED_DEST" //The specified Destination is already in use
|
||||
ResultI2PError = "I2P_ERROR" //A generic I2P error (e.g. I2CP disconnection, etc.)
|
||||
ResultInvalidKey = "INVALID_KEY" //The specified key is not valid (bad format, etc.)
|
||||
ResultKeyNotFound = "KEY_NOT_FOUND" //The naming system can't resolve the given name
|
||||
ResultPeerNotFound = "PEER_NOT_FOUND" //The peer cannot be found on the network
|
||||
ResultTimeout = "TIMEOUT" // Timeout while waiting for an event (e.g. peer answer)
|
||||
)
|
||||
|
||||
type ReplyError struct {
|
||||
Result string
|
||||
Reply *Reply
|
||||
}
|
||||
|
||||
func (r ReplyError) Error() string {
|
||||
return fmt.Sprintf("ReplyError: Result:%s - Reply:%+v", r.Result, r.Reply)
|
||||
}
|
||||
|
||||
func (c *Client) Lookup(name string) (addr string, err error) {
|
||||
var r *Reply
|
||||
|
||||
|
@ -5,6 +5,30 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// The Possible Results send by SAM
|
||||
const (
|
||||
ResultOk = "OK" //Operation completed successfully
|
||||
ResultCantReachPeer = "CANT_REACH_PEER" //The peer exists, but cannot be reached
|
||||
ResultDuplicatedId = "DUPLICATED_ID" //If the nickname is already associated with a session :
|
||||
ResultDuplicatedDest = "DUPLICATED_DEST" //The specified Destination is already in use
|
||||
ResultI2PError = "I2P_ERROR" //A generic I2P error (e.g. I2CP disconnection, etc.)
|
||||
ResultInvalidKey = "INVALID_KEY" //The specified key is not valid (bad format, etc.)
|
||||
ResultKeyNotFound = "KEY_NOT_FOUND" //The naming system can't resolve the given name
|
||||
ResultPeerNotFound = "PEER_NOT_FOUND" //The peer cannot be found on the network
|
||||
ResultTimeout = "TIMEOUT" // Timeout while waiting for an event (e.g. peer answer)
|
||||
)
|
||||
|
||||
// Custom error type, containing the Result and full Reply
|
||||
type ReplyError struct {
|
||||
Result string
|
||||
Reply *Reply
|
||||
}
|
||||
|
||||
func (r ReplyError) Error() string {
|
||||
return fmt.Sprintf("ReplyError: Result:%s - Reply:%+v", r.Result, r.Reply)
|
||||
}
|
||||
|
||||
// Parsed Reply type containing a map of all the key-value pairs
|
||||
type Reply struct {
|
||||
Topic string
|
||||
Type string
|
||||
|
@ -6,7 +6,8 @@ import (
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
func (c *Client) createStreamSession(dest string) (id int32, newDest string, err error) {
|
||||
// Create a new STREAM Session. Returns the Id for the new Client.
|
||||
func (c *Client) CreateStreamSession(dest string) (id int32, newDest string, err error) {
|
||||
if dest == "" {
|
||||
dest = "TRANSIENT"
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Asks SAM for a TCP-Like connection to dest, has to be called on a new Client
|
||||
func (c *Client) StreamConnect(id int32, dest string) (err error) {
|
||||
var r *Reply
|
||||
|
||||
@ -21,6 +22,5 @@ func (c *Client) StreamConnect(id int32, dest string) (err error) {
|
||||
return ReplyError{result, r}
|
||||
}
|
||||
|
||||
fmt.Println("StreamConnect OK")
|
||||
return nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user