Skip to content

Commit

Permalink
The OctoPrint server is simulated. See -octoprint
Browse files Browse the repository at this point in the history
  • Loading branch information
macdylan committed Apr 17, 2023
1 parent b57e373 commit 6d93264
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 62 deletions.
14 changes: 11 additions & 3 deletions connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,37 @@ type Handler interface {
Ping(*Printer) bool
Connect() error
Disconnect() error
Upload(fpath string) error
Upload(fname string, content []byte) error
}

func (c *connector) RegisterHandler(h Handler) {
c.handlers = append(c.handlers, h)
}

func (c *connector) Upload(p *Printer, fpath string) error {
// Upload to upload a file to a printer
func (c *connector) Upload(p *Printer, fname string, content []byte) error {
// Iterate through all handlers
for _, h := range c.handlers {
// Check if handler can ping the printer
if h.Ping(p) {
// Connect to the printer
if err := h.Connect(); err != nil {
return err
}
if err := h.Upload(fpath); err != nil {
// Upload the file to the printer
if err := h.Upload(fname, content); err != nil {
h.Disconnect()
return err
}
// Disconnect from the printer
if err := h.Disconnect(); err != nil {
return err
}
// Return nil if successful
return nil
}
}
// Return error if printer is not available
return errors.New("Printer " + p.IP + " is not available.")
}

Expand Down
24 changes: 16 additions & 8 deletions connector_http.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package main

import (
"bytes"
"fmt"
"io"
"log"
"os"
"time"
Expand Down Expand Up @@ -87,7 +89,7 @@ func (hc *HTTPConnector) Disconnect() (err error) {
return
}

func (hc *HTTPConnector) Upload(fpath string) (err error) {
func (hc *HTTPConnector) Upload(fname string, content []byte) (err error) {
finished := make(chan bool, 1)
defer func() {
finished <- true
Expand All @@ -105,13 +107,24 @@ func (hc *HTTPConnector) Upload(fpath string) (err error) {
}
}()

file := req.FileUpload{
ParamName: "file",
FileName: fname,
GetFileContent: func() (io.ReadCloser, error) {
return io.NopCloser(bytes.NewReader(content)), nil
},
FileSize: int64(len(content)),
}

w := uilive.New()
w.Start()
defer w.Stop()
req := hc.request(0).SetFile("file", fpath).SetUploadCallback(func(i req.UploadInfo) {
req := hc.request(0).SetFileUpload(file).SetUploadCallback(func(info req.UploadInfo) {
log.SetOutput(w)
defer log.SetOutput(os.Stderr)
hc.progress(i)

perc := float64(info.UploadedSize) / float64(info.FileSize) * 100.0
log.Printf(" - HTTP sending %.1f%%", perc)
})

// disable chucked to make Content-Length
Expand All @@ -120,11 +133,6 @@ func (hc *HTTPConnector) Upload(fpath string) (err error) {
return
}

func (hc *HTTPConnector) progress(info req.UploadInfo) {
perc := float64(info.UploadedSize) / float64(info.FileSize) * 100.0
log.Printf(" - HTTP sending %.1f%%", perc)
}

func (hc *HTTPConnector) request(timeout ...int) *req.Request {
to := HTTPTimeout
if len(timeout) > 0 {
Expand Down
11 changes: 2 additions & 9 deletions connector_sacp.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"log"
"net"
"os"
"path"
"time"

"github.com/gosuri/uilive"
Expand Down Expand Up @@ -43,13 +42,7 @@ func (sc *SACPConnector) Disconnect() error {
return nil
}

func (sc *SACPConnector) Upload(fpath string) (err error) {
data, err := os.ReadFile(fpath)
if err != nil {
return err
}
fname := path.Base(fpath)

func (sc *SACPConnector) Upload(fname string, content []byte) (err error) {
w := uilive.New()
w.Start()
log.SetOutput(w)
Expand All @@ -58,7 +51,7 @@ func (sc *SACPConnector) Upload(fpath string) (err error) {
log.SetOutput(os.Stderr)
}()

err = SACP_start_upload(sc.conn, fname, data, SACPTimeout*time.Second)
err = SACP_start_upload(sc.conn, fname, content, SACPTimeout*time.Second)
return
}

Expand Down
11 changes: 8 additions & 3 deletions localstorage.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,31 @@ func NewLocalStorage(savePath string) *LocalStorage {
return s
}

// Add to add printers to LocalStorage
func (ls *LocalStorage) Add(printers ...*Printer) {
// Iterate over each printer
for _, p := range printers {
// Skip if printer ID is empty
if p.ID == "" {
continue
}

// Iterate over each printer in LocalStorage
for idx, x := range ls.Printers {
// If printer ID matches, update IP and Token if necessary
if x.ID == p.ID {
if x.IP != p.IP {
ls.Printers[idx].IP = p.IP
}
if p.Token != "" && x.Token != p.Token {
ls.Printers[idx].Token = p.Token
}
// Go to exists label
goto exists
}
}

// Append printer to LocalStorage
ls.Printers = append(ls.Printers, p)

// Label for when printer already exists
exists:
}
}
Expand Down
88 changes: 49 additions & 39 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@ package main

import (
"flag"
"fmt"
"log"
"os"
"os/signal"
"path"
"path/filepath"
"syscall"
"time"

"github.com/manifoldco/promptui"
)

var (
Host string
KnownHosts string
DiscoverTimeout time.Duration
Host string
KnownHosts string
DiscoverTimeout time.Duration
OctoPrintListenAddr string

_Payloads []string
)
Expand All @@ -37,30 +39,11 @@ func main() {
flag.StringVar(&Host, "host", "", "upload to host(id/ip/hostname), not required.")
flag.StringVar(&KnownHosts, "knownhosts", defaultKnownHosts, "known hosts")
flag.DurationVar(&DiscoverTimeout, "timeout", time.Second*4, "printer discovery timeout")
flag.StringVar(&OctoPrintListenAddr, "octoprint", "", "octoprint listen address, e.g. '-octoprint :8844' then you can upload files to printer by http://localhost:8844")

flag.Usage = flag_usage
flag.Parse()

args := flag.Args()
// prusaslicer
if outputName := os.Getenv("SLIC3R_PP_OUTPUT_NAME"); outputName != "" {
args = []string{outputName}
}

// 检查这些文件参数是否存在
for _, file := range args {
if _, err := os.Stat(file); os.IsNotExist(err) {
log.Panicf("File %s does not exist\n", file)
} else {
_Payloads = append(_Payloads, file)
}
}

// 检查是否有传入的文件
if len(_Payloads) == 0 {
log.Panicln("No input files")
}

var printer *Printer
ls := NewLocalStorage(KnownHosts)
defer func() {
Expand Down Expand Up @@ -120,29 +103,56 @@ func main() {
log.Println("Printer Model:", printer.Model)
}

// Create a channel to listen for signals
sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
go func() {
sig := <-sc
log.Printf("Received signal: %s", sig)
// update printer's token
if printer != nil {
ls.Add(printer)
}
ls.Save()
os.Exit(0)
}()

if OctoPrintListenAddr != "" {
// listen for octoprint uploads
if err := startOctoPrintServer(OctoPrintListenAddr, printer); err != nil {
log.Panic(err)
}
return
}

// 检查文件参数是否存在
for _, file := range flag.Args() {
if _, err := os.Stat(file); os.IsNotExist(err) {
log.Panicf("File %s does not exist\n", file)
} else {
_Payloads = append(_Payloads, file)
}
}

// 检查是否有传入的文件
if len(_Payloads) == 0 {
log.Panicln("No input files")
}

// Upload files to host
for _, filepath := range _Payloads {
content, err := os.ReadFile(filepath)
if err != nil {
log.Panicln(err)
}
st, _ := os.Stat(filepath)
fname := path.Base(filepath)
fname := normalizedFilename(path.Base(filepath))
log.Printf("Uploading file '%s' [%s]...", fname, humanReadableSize(st.Size()))
if err := Connector.Upload(printer, filepath); err != nil {
if err := Connector.Upload(printer, fname, content); err != nil {
log.Panicln(err)
} else {
log.Println("Upload finished.")
<-time.After(time.Second * 1)
}
}
}

func humanReadableSize(size int64) string {
const unit = 1024
if size < unit {
return fmt.Sprintf("%d B", size)
}
div, exp := int64(unit), 0
for n := size / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %cB", float64(size)/float64(div), "KMGTPE"[exp])
}
70 changes: 70 additions & 0 deletions octoprint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package main

import (
"io"
"log"
"net"
"net/http"
"time"
)

func LoggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
// Log the request
log.Printf("Request %s %s completed in %v", r.Method, r.URL.Path, time.Since(start))
})
}

func startOctoPrintServer(listenAddr string, printer *Printer) error {
mux := http.NewServeMux()
mux.HandleFunc("/api/version", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"api": "0.1", "server": "1.2.3", "text": "OctoPrint 1.2.3/Dummy"}`))
})

mux.HandleFunc("/api/files/local", func(w http.ResponseWriter, r *http.Request) {
// Check if request is a POST request
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}

// Retrieve the uploaded file
file, fd, err := r.FormFile("file")
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
defer file.Close()
fd.Filename = normalizedFilename(fd.Filename)

// Send the stream to the printer
content, _ := io.ReadAll(file)
if err := Connector.Upload(printer, fd.Filename, content); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

log.Printf("Upload finished: %s [%s]", fd.Filename, humanReadableSize(int64(len(content))))

// Return success response
w.WriteHeader(http.StatusOK)
})

handler := LoggingMiddleware(mux)

log.Printf("Starting OctoPrint server on %s ...", listenAddr)

// Create a listener
listener, err := net.Listen("tcp", listenAddr)
if err != nil {
return err
}

log.Printf("Server started, now you can upload files to http://localhost:%s", listenAddr)

// Start the server
return http.Serve(listener, handler)
}
25 changes: 25 additions & 0 deletions utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package main

import (
"fmt"
"regexp"
)

func humanReadableSize(size int64) string {
const unit = 1024
if size < unit {
return fmt.Sprintf("%d B", size)
}
div, exp := int64(unit), 0
for n := size / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %cB", float64(size)/float64(div), "KMGTPE"[exp])
}

var reFilename = regexp.MustCompile(`^[\.\/\\~]+`)

func normalizedFilename(filename string) string {
return reFilename.ReplaceAllString(filename, "")
}

0 comments on commit 6d93264

Please sign in to comment.