This commit is contained in:
Sotig
2026-03-21 15:35:50 +02:00
commit 07cd9ebac9
10 changed files with 259 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
configs/*

2
README.md Normal file
View File

@@ -0,0 +1,2 @@
## 3D slicer Api
This is a simple api that slices 3d files using prusa-slicer, fff and sla modes are supported.

42
cmd/actions.go Normal file
View File

@@ -0,0 +1,42 @@
package main
import "net/http"
func actions(mux *http.ServeMux) {
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
})
mux.HandleFunc("/analyze-fff", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
})
mux.HandleFunc("/analyze-sla", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
})
}

28
cmd/main.go Normal file
View File

@@ -0,0 +1,28 @@
package main
import (
"fmt"
"net/http"
"os"
"golang.org/x/net/http2"
)
func main() {
// Your code here
mux := http.NewServeMux()
svr := &http.Server{
Addr: fmt.Sprintf("%s:%s", os.Getenv("HOST"), os.Getenv("PORT")),
Handler: mux,
}
http2.ConfigureServer(svr, nil)
actions(mux) // Register actions with the multiplexer
fmt.Printf("Starting server on %s:%s\n", os.Getenv("HOST"), os.Getenv("PORT"))
err := svr.ListenAndServe()
if err != nil {
panic(err)
}
}

39
docker/Dockerfile Normal file
View File

@@ -0,0 +1,39 @@
FROM ubuntu:plucky
RUN echo "deb https://ppa.launchpadcontent.net/longsleep/golang-backports/ubuntu ubuntu-plucky main" | tee /etc/apt/sources.list.d/docker.list
RUN apt update
ENV GO_VERSION=1.24
RUN apt install -y golang-${GO_VERSION}
RUN ln -s "/usr/lib/go-${GO_VERSION}/bin/go" /usr/local/bin/
RUN apt-get clean && apt-get update && apt-get install -y locales wget
RUN locale-gen en_US.UTF-8
RUN update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
ENV LANG=en_US.UTF-8
ENV LC_CTYPE="en_US.UTF-8"
ENV LC_NUMERIC="en_US.UTF-8"
ENV LC_TIME="en_US.UTF-8"
ENV LC_COLLATE="en_US.UTF-8"
ENV LC_MONETARY="en_US.UTF-8"
ENV LC_MESSAGES="en_US.UTF-8"
ENV LC_PAPER="en_US.UTF-8"
ENV LC_NAME="en_US.UTF-8"
ENV LC_ADDRESS="en_US.UTF-8"
ENV LC_TELEPHONE="en_US.UTF-8"
ENV LC_MEASUREMENT="en_US.UTF-8"
ENV LC_IDENTIFICATION="en_US.UTF-8"
ENV LC_ALL=
RUN apt install -y prusa-slicer
WORKDIR /build
COPY ../ .
RUN go build -o /bin/slic3r-api ./cmd
RUN rm -rf /build/*
CMD [ "/bin/slic3r-api" ]

15
docker/docker-compose.yml Normal file
View File

@@ -0,0 +1,15 @@
services:
slic3r-api:
build:
context: ../
dockerfile: docker/Dockerfile
command: /bin/bash -c "cd /src && go run ./cmd"
volumes:
- ../:/src
- ../configs:/configs
environment:
- PORT=3030
- HOST=0.0.0.0
- CONFIGS=/configs/
ports:
- 3030:3030

8
go.mod Normal file
View File

@@ -0,0 +1,8 @@
module github.com/sotigr/slic3r-api
go 1.24.2
require (
golang.org/x/net v0.41.0 // indirect
golang.org/x/text v0.26.0 // indirect
)

4
go.sum Normal file
View File

@@ -0,0 +1,4 @@
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=

104
internal/cli/cli.go Normal file
View File

@@ -0,0 +1,104 @@
package cli
import (
"context"
"errors"
"io"
"os/exec"
"regexp"
"strings"
)
var re = regexp.MustCompile(`\w|\%|^(\+|,|\.|:|\/|\\|=|_|-|[a-z]|[A-Z]|[0-9]|\s)+$`)
func validateCliArgument(arg string) bool {
return re.Match([]byte(arg))
}
func validateCliArguments(args []string) bool {
for _, p := range args {
if !validateCliArgument(p) {
return false
}
}
return true
}
func execNoCheck(ctx context.Context, command string, args []string) (string, string, error) {
cmd := exec.CommandContext(ctx, command, args...)
cmdStr := cmd.String()
pStdout, err := cmd.StdoutPipe()
if err != nil {
return "", cmdStr, err
}
pStderr, err := cmd.StderrPipe()
if err != nil {
return "", cmdStr, err
}
err = cmd.Start()
if err != nil {
return "", cmdStr, err
}
stdout, _ := io.ReadAll(pStdout)
stderr, _ := io.ReadAll(pStderr)
err = cmd.Wait()
if err != nil {
return "", cmdStr, errors.New(err.Error() + " | " + string(stderr) + " | " + string(stdout))
}
return string(stdout), cmdStr, nil
}
type Pipe struct {
Command string
Args []string
}
func (p *Pipe) IsSanatory() bool {
return validateCliArguments(p.Args) && validateCliArgument(p.Command)
}
func (p *Pipe) Execute(ctx context.Context) (string, string, error) {
if !p.IsSanatory() {
return "", "", errors.New("failed to execute cli command: " + p.Command + " " + strings.Join(p.Args, " ") + " some arguments are not allowed")
} else {
return execNoCheck(ctx, p.Command, p.Args)
}
}
func ExecuteCLIPipeLine(ctx context.Context, pipes []Pipe) (string, string, error) {
pipeLen := len(pipes)
if pipeLen == 0 {
return "", "", errors.New("failed to execute cli command: no pipes provided")
}
argLen := 0
for _, p := range pipes {
if !p.IsSanatory() {
return "", "", errors.New("failed to execute cli command: " + p.Command + " " + strings.Join(p.Args, " ") + " some arguments are not allowed")
}
argLen += len(p.Args) + 1
}
command := "/bin/sh"
var args []string = []string{}
args = append(args, "-c")
pipeLen -= 1
cmdArg := ""
for i, p := range pipes {
cmdArg += p.Command + " " + strings.Join(p.Args, " ")
if i != pipeLen {
cmdArg += " | "
}
}
args = append(args, cmdArg)
return execNoCheck(ctx, command, args)
}

16
notes.txt Normal file
View File

@@ -0,0 +1,16 @@
look at:
* https://github.com/prusa3d/PrusaSlicer/wiki/Command-Line-Interface
* https://manual.slic3r.org/advanced/command-line
slice:
* prusa-slicer --load config.ini --export-gcode --info part.stl
* prusa-slicer --load config.ini --info --export-sla part.stl
thumbnail:
* f3d 'model.stl' --resolution=512,512 -a --anti-aliasing-mode=taa --filename=false --metadata=false --color=#999 -t --grid=false --axis=false --no-background --output='output.png'
post-process:
* this can preview print times for sla: https://github.com/oelmekki/sl1toctb?tab=readme-ov-file