Skip to content

Commit

Permalink
yeeaaafdkjass I am so tired
Browse files Browse the repository at this point in the history
  • Loading branch information
tjhorner committed Apr 28, 2019
1 parent a6753f3 commit 7f4272e
Show file tree
Hide file tree
Showing 13 changed files with 1,077 additions and 9 deletions.
49 changes: 47 additions & 2 deletions README.md
Expand Up @@ -10,7 +10,48 @@ A Go client library to interact with your MakerBot printer via the network.

Documentation, examples and more at [GoDoc](https://godoc.org/github.com/tjhorner/makerbot-rpc).

**This is currently in beta and does not support many functions that MakerBot printers make available.** ~~Most notably, it does not yet support sending print files.~~ Also, some responses are not yet modelled.
Since this is currently mid-development, things will probably change _very, very often._ No stable API is guaranteed until the first stable version of this project.

## Example

```shell
go get github.com/tjhorner/makerbot-rpc
```

```golang
// WARNING: This example may fail to work at any time.
// This library is still in development. This example
// is only provided to give a sense of what the library can do.
// Errors are ignored for brevity.

client := makerbot.Client{}
defer client.Close()

// React when the printer's state changes
client.HandleStateChange(func(olsd new, *makerbot.PrinterMetadata) {
if new.CurrentProcess == nil {
return
}

// Log the thing the printer is currently doing
log.Printf("Current process: %s, %v%% done\n", new.CurrentProcess.Name, new.CurrentProcess.Progress)
})

// Make initial TCP connection w/ printer
client.ConnectLocal("192.168.1.2", "9999") // most MakerBot printers listen on 9999

log.Printf("Connected to MakerBot printer: %s\n", client.Printer.MachineName)

// Authenticate with Thingiverse
client.AuthenticateWithThingiverse("my_access_token", "my_username")

log.Println("Queuing file for printing...")

// Print a file named `print.makerbot` in the same directory
client.PrintFile("print.makerbot")

log.Println("Done! Bye bye.")
```

## Features and TODO

Expand All @@ -29,4 +70,8 @@ Documentation, examples and more at [GoDoc](https://godoc.org/github.com/tjhorne
- [ ] Get machine config (low priority; isn't very useful)
- [ ] Write tests (will need to make a mock MakerBot RPC server)
- [ ] Write examples
- [ ] Better errors
- [ ] Better errors

## License

TBD, but probably MIT later.
23 changes: 20 additions & 3 deletions client.go
Expand Up @@ -9,6 +9,7 @@ import (
"path/filepath"
"strings"

"github.com/tjhorner/makerbot-rpc/printfile"
"github.com/tjhorner/makerbot-rpc/reflector"

"github.com/tjhorner/makerbot-rpc/jsonrpc"
Expand Down Expand Up @@ -127,7 +128,7 @@ func (c *Client) handshake() error {
go c.endCameraStream()
}

metadata := parseCameraFrameMetadata(c.rpc.GetRawData(16))
metadata := unpackCameraFrameMetadata(c.rpc.GetRawData(16))

data := c.rpc.GetRawData(int(metadata.FileSize))

Expand Down Expand Up @@ -336,8 +337,6 @@ type rpcPutTermParams struct {
Length int `json:"length"`
}

// TODO this could probably be done better with an io reader

// Print will synchronously print a .makerbot file with the provided
// `filename` (can be anything). `data` should be the contents of the
// .makerbot file. The function returns when it is done sending the entire
Expand Down Expand Up @@ -393,10 +392,28 @@ func (c *Client) Print(filename string, data []byte) error {
// `filename` and automatically reading from it then
// feeding it to Print.
func (c *Client) PrintFile(filename string) error {
// TODO support streaming files in so we don't need to
// load the entire thing into memory
data, err := ioutil.ReadFile(filename)
if err != nil {
return err
}

return c.Print(filepath.Base(filename), data)
}

// PrintFileVerify is exactly like PrintFile except it errors
// if the print file is not designed for the printer that this
// Client is connected to.
func (c *Client) PrintFileVerify(filename string) error {
metadata, err := printfile.GetFileMetadata(filename)
if err != nil {
return err
}

if metadata.BotType != c.Printer.BotType {
return errors.New("print file is not designed for this MakerBot printer")
}

return c.PrintFile(filename)
}
5 changes: 3 additions & 2 deletions jsonrpc/client.go
Expand Up @@ -36,7 +36,9 @@ type rpcError struct {
} `json:"data"`
}

func (e *rpcError) Error() string { return fmt.Sprintf("rpc error: %s: %s", e.Data.Name, e.Message) }
func (e *rpcError) Error() string {
return fmt.Sprintf("rpc error (remote): %s: %s", e.Data.Name, e.Message)
}

type rpcResponse struct {
ID *string `json:"id"`
Expand Down Expand Up @@ -81,7 +83,6 @@ func (c *Client) Connect() error {
json.Unmarshal(j, &req)

if sub, ok := c.subs[req.Method]; ok {

go sub(req.Params)
}
} else if resp.ID != nil {
Expand Down
2 changes: 1 addition & 1 deletion jsonrpc/jsonreader.go
Expand Up @@ -112,7 +112,6 @@ func (r *JSONReader) transition(b byte) {
// FeedByte feeds the JSONReader a single byte
func (r *JSONReader) FeedByte(b byte) {
r.buffer = append(r.buffer, b)

r.transition(b)
}

Expand All @@ -127,6 +126,7 @@ func (r *JSONReader) FeedBytes(bs []byte) {
// `length` is reached. The captured data is returned as an
// array of bytes.
func (r *JSONReader) GetRawData(length int) []byte {
// TODO should we mutex lock reading from TCP socket?
ch := make(chan []byte)
r.rawCh = &ch
r.state = state4
Expand Down
106 changes: 106 additions & 0 deletions jsonrpc/jsonreader_test.go
@@ -0,0 +1,106 @@
package jsonrpc_test

import (
"crypto/rand"
"errors"
"reflect"
"sync"
"testing"

"github.com/tjhorner/makerbot-rpc/jsonrpc"
)

func TestJSONReader(t *testing.T) {
testJson := `[
{
"_id": "5cc4918e5ffc07a556e7a467",
"index": 0,
"guid": "ccaaa030-db12-4e41-901a-71db5eddd1a5",
"isActive": false,
"balance": "$2,952.59",
"picture": "http://placehold.it/32x32",
"age": 36,
"eyeColor": "green",
"name": {
"first": "Rush",
"last": "Best"
},
"company": "AQUASURE",
"email": "rush.best@aquasure.us",
"phone": "+1 (963) 588-3601",
"address": "438 Murdock Court, Winchester, New Mexico, 1957",
"about": "Proident exercitation et Lorem est. Deserunt occaecat culpa aute fugiat. Ea adipisicing culpa veniam est et qui anim ut sit tempor ut laboris est dolore. Cillum nulla incididunt eiusmod et cillum sit incididunt ullamco incididunt ex quis deserunt excepteur. Laboris anim esse duis duis Lorem in elit adipisicing laboris sit cupidatat esse tempor incididunt. Cillum elit laborum voluptate sint commodo exercitation laboris adipisicing non ipsum.",
"registered": "Monday, August 1, 2016 11:54 PM",
"latitude": "-2.77938",
"longitude": "-177.303158",
"tags": [
"fugiat",
"elit",
"qui",
"in",
"officia"
],
"range": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9
],
"friends": [
{
"id": 0,
"name": "Dorothea Maxwell"
},
{
"id": 1,
"name": "Fry Blair"
},
{
"id": 2,
"name": "Jessie Ware"
}
],
"greeting": "Hello, Rush! You have 5 unread messages.",
"favoriteFruit": "banana"
}
]`

var wg sync.WaitGroup

wg.Add(1)
reader := jsonrpc.NewJSONReader(func(data []byte) error {
if string(data) != testJson {
t.Errorf("JSONReader's json was incorrect, got: %s, want: [long test string]\n", string(data))
}

wg.Done()
return nil
})

reader.FeedBytes([]byte(testJson))

wg.Wait()
}

func TestJSONReader_GetRawData(t *testing.T) {
randBytes := make([]byte, 32) // 32 random bytes
rand.Read(randBytes)

reader := jsonrpc.NewJSONReader(func(d []byte) error { return errors.New("") })

go func() {
reader.FeedBytes(randBytes)
}()

result := reader.GetRawData(32)

if !reflect.DeepEqual(randBytes, result) {
t.Errorf("JSONReader did not return randBytes\n")
}
}

0 comments on commit 7f4272e

Please sign in to comment.