remarkable_printer/main.go

215 lines
4.5 KiB
Go

// Evan Widloski - 2020-03-10
// thanks to https://coderwall.com/p/wohavg/creating-a-simple-tcp-server-in-go
package main
import (
"bufio"
"flag"
"fmt"
"io"
"net"
"os"
"os/exec"
"strconv"
"strings"
"time"
"github.com/google/uuid"
)
var (
CONN_HOST = "0.0.0.0"
CONN_PORT = "9100"
LOG_LEVEL = "error"
XOCHITL_DIR = "/home/root/.local/share/remarkable/xochitl/"
)
const METADATA_TEMPLATE = `{
"deleted": false,
"lastModified": "%d000",
"lastOpened": "0",
"lastOpenedPage": 0,
"metadatamodified": true,
"modified": true,
"parent": "",
"pinned": false,
"synced": false,
"type": "DocumentType",
"version": 0,
"visibleName": "%v"
}
`
const CONTENT_TEMPLATE = "{}"
func main() {
// ----- Parse options -----
debug_flag := flag.Bool("debug", false, "enable debug output")
test := flag.Bool("test", false, "use /tmp as output dir")
restart := flag.Bool("restart", false, "restart xochitl after saving PDF")
CONN_HOST := flag.String("host", CONN_HOST, "override bind address")
CONN_PORT := flag.String("port", CONN_PORT, "override bind port")
flag.Parse()
if *debug_flag {
LOG_LEVEL = "debug"
debug("Debugging enabled")
}
if *test {
XOCHITL_DIR = "/tmp/"
}
// ----- Listen for connections -----
// Listen for incoming connections.
var l net.Listener
var err error
var isSocketActivated = os.Getenv("LISTEN_PID") == strconv.Itoa(os.Getpid())
if isSocketActivated {
l, err = net.FileListener(os.NewFile(3, "systemd-socket"))
fmt.Println("Listening on systemd-socket")
conn, err := l.Accept()
if err != nil {
fmt.Println("Error accepting: ", err.Error())
os.Exit(1)
}
handleRequest(conn)
if *restart {
restartUISoftware()
}
} else {
l, err = net.Listen("tcp", *CONN_HOST+":"+*CONN_PORT)
fmt.Println("Listening on " + *CONN_HOST + ":" + *CONN_PORT)
for {
// Listen for an incoming connection.
conn, err := l.Accept()
if err != nil {
fmt.Println("Error accepting: ", err.Error())
os.Exit(1)
}
handleRequest(conn)
if *restart {
restartUISoftware()
}
}
}
check(err)
defer l.Close() // Close the listener when the application closes.
}
func debug(msg ...string) {
if LOG_LEVEL == "debug" {
for _, value := range msg {
fmt.Print(value)
fmt.Print(" ")
}
fmt.Println()
}
}
func check(e error) {
if e != nil {
panic(e)
}
}
// Handles incoming requests.
func handleRequest(conn net.Conn) {
u, _ := uuid.NewRandom()
pdf_path := XOCHITL_DIR + u.String() + ".pdf"
fmt.Println("Saving PDF to:", pdf_path)
// ----- Create .pdf -----
f, err := os.Create(pdf_path)
check(err)
reader := bufio.NewReader(conn)
// Default name of new document
title := "Printed"
// Read until start of PDF
for {
line, err := reader.ReadString('\n')
debug(strings.TrimRight(line, "\n"))
// set print job name as file title
if strings.HasPrefix(line, "@PJL JOB NAME") {
title = strings.Split(line, "\"")[1]
debug("Setting title to:", title)
}
// PDF section started
if strings.HasPrefix(line, "%PDF-") {
debug("PDF begin")
_, err := f.WriteString(line)
check(err)
break
}
if err == io.EOF {
fmt.Println("Couldn't find PDF start")
os.Exit(1)
}
check(err)
}
// Read until end of PDF
for {
line, err := reader.ReadString('\n')
_, err = f.WriteString(line)
check(err)
// end of pdf file
if strings.HasPrefix(line, "%%EOF") {
f.Close()
break
}
if err == io.EOF {
debug(line)
debug("Couldn't find PDF end")
os.Exit(1)
}
check(err)
}
// ----- Create .metadata -----
meta_path := XOCHITL_DIR + u.String() + ".metadata"
fmt.Println("Saving metadata to", meta_path)
f, err = os.Create(meta_path)
f.WriteString(fmt.Sprintf(METADATA_TEMPLATE, time.Now().Unix(), title))
f.Close()
// ----- Create .content -----
cont_path := XOCHITL_DIR + u.String() + ".content"
fmt.Println("Saving content file to", cont_path)
f, err = os.Create(cont_path)
f.WriteString(fmt.Sprintf(CONTENT_TEMPLATE))
f.Close()
conn.Close()
}
// Restarts xochitl or other UI software
func restartUISoftware() {
services := []string{"xochitl", "remux", "tarnish", "draft"}
for _, service := range services {
_, exitcode := exec.Command("systemctl", "is-active", service).CombinedOutput()
if exitcode == nil {
fmt.Println("Restarting " + service)
stdout, err := exec.Command("systemctl", "restart", service).CombinedOutput()
if err != nil {
fmt.Println(service+" restart failed with message:", string(stdout))
}
}
}
}