all repos — honk @ 7d1e2617a8f139ab7c225d01d673b354a34ecdda

my fork of honk

backend.go (view raw)

  1//
  2// Copyright (c) 2019 Ted Unangst <tedu@tedunangst.com>
  3//
  4// Permission to use, copy, modify, and distribute this software for any
  5// purpose with or without fee is hereby granted, provided that the above
  6// copyright notice and this permission notice appear in all copies.
  7//
  8// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 10// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 11// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 12// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 13// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 14// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 15
 16package main
 17
 18import (
 19	"bytes"
 20	"net"
 21	"net/rpc"
 22	"os"
 23	"os/exec"
 24
 25	"humungus.tedunangst.com/r/webs/gate"
 26	"humungus.tedunangst.com/r/webs/image"
 27)
 28
 29type Shrinker struct {
 30}
 31
 32type ShrinkerArgs struct {
 33	Buf    []byte
 34	Params image.Params
 35}
 36
 37type ShrinkerResult struct {
 38	Image *image.Image
 39}
 40
 41var shrinkgate = gate.NewLimiter(4)
 42
 43func (s *Shrinker) Shrink(args *ShrinkerArgs, res *ShrinkerResult) error {
 44	shrinkgate.Start()
 45	defer shrinkgate.Finish()
 46	img, err := image.Vacuum(bytes.NewReader(args.Buf), args.Params)
 47	if err != nil {
 48		return err
 49	}
 50	res.Image = img
 51	return nil
 52}
 53
 54func backendSockname() string {
 55	return dataDir + "/backend.sock"
 56}
 57
 58func shrinkit(data []byte) (*image.Image, error) {
 59	cl, err := rpc.Dial("unix", backendSockname())
 60	if err != nil {
 61		return nil, err
 62	}
 63	defer cl.Close()
 64	var res ShrinkerResult
 65	err = cl.Call("Shrinker.Shrink", &ShrinkerArgs{
 66		Buf:    data,
 67		Params: image.Params{LimitSize: 4200 * 4200, MaxWidth: 2048, MaxHeight: 2048},
 68	}, &res)
 69	if err != nil {
 70		return nil, err
 71	}
 72	return res.Image, nil
 73}
 74
 75var backendhooks []func()
 76
 77func orphancheck() {
 78	var b [1]byte
 79	os.Stdin.Read(b[:])
 80	dlog.Printf("backend shutting down")
 81	os.Exit(0)
 82}
 83
 84func backendServer() {
 85	dlog.Printf("backend server running")
 86	go orphancheck()
 87	shrinker := new(Shrinker)
 88	srv := rpc.NewServer()
 89	err := srv.Register(shrinker)
 90	if err != nil {
 91		elog.Panicf("unable to register shrinker: %s", err)
 92	}
 93
 94	sockname := backendSockname()
 95	err = os.Remove(sockname)
 96	if err != nil && !os.IsNotExist(err) {
 97		elog.Panicf("unable to unlink socket: %s", err)
 98	}
 99
100	lis, err := net.Listen("unix", sockname)
101	if err != nil {
102		elog.Panicf("unable to register shrinker: %s", err)
103	}
104	err = setLimits()
105	if err != nil {
106		elog.Printf("error setting backend limits: %s", err)
107	}
108	for _, h := range backendhooks {
109		h()
110	}
111	srv.Accept(lis)
112}
113
114func runBackendServer() {
115	r, w, err := os.Pipe()
116	if err != nil {
117		elog.Panicf("can't pipe: %s", err)
118	}
119	proc := exec.Command(os.Args[0], reexecArgs("backend")...)
120	proc.Stdout = os.Stdout
121	proc.Stderr = os.Stderr
122	proc.Stdin = r
123	err = proc.Start()
124	if err != nil {
125		elog.Panicf("can't exec backend: %s", err)
126	}
127	go func() {
128		proc.Wait()
129		elog.Printf("lost the backend: %s", err)
130		w.Close()
131	}()
132}