Added some Documentation and Example of using it with http.Transport

This commit is contained in:
Henry
2014-02-11 14:48:13 +01:00
parent b0e9ab001e
commit a421daf8d9
7 changed files with 102 additions and 26 deletions

View File

@ -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)

View File

@ -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()
}

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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"
}

View File

@ -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
}