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 "log"
21 "net"
22 "net/rpc"
23 "os"
24 "os/exec"
25
26 "humungus.tedunangst.com/r/webs/gate"
27 "humungus.tedunangst.com/r/webs/image"
28)
29
30type Shrinker struct {
31}
32
33type ShrinkerArgs struct {
34 Buf []byte
35 Params image.Params
36}
37
38type ShrinkerResult struct {
39 Image *image.Image
40}
41
42var shrinkgate = gate.NewLimiter(4)
43
44func (s *Shrinker) Shrink(args *ShrinkerArgs, res *ShrinkerResult) error {
45 shrinkgate.Start()
46 defer shrinkgate.Finish()
47 img, err := image.Vacuum(bytes.NewReader(args.Buf), args.Params)
48 if err != nil {
49 return err
50 }
51 res.Image = img
52 return nil
53}
54
55func backendSockname() string {
56 return dataDir + "/backend.sock"
57}
58
59func shrinkit(data []byte) (*image.Image, error) {
60 cl, err := rpc.Dial("unix", backendSockname())
61 if err != nil {
62 return nil, err
63 }
64 defer cl.Close()
65 var res ShrinkerResult
66 err = cl.Call("Shrinker.Shrink", &ShrinkerArgs{
67 Buf: data,
68 Params: image.Params{LimitSize: 4200 * 4200, MaxWidth: 2048, MaxHeight: 2048},
69 }, &res)
70 if err != nil {
71 return nil, err
72 }
73 return res.Image, nil
74}
75
76var backendhooks []func()
77
78func backendServer() {
79 log.Printf("backend server running")
80 shrinker := new(Shrinker)
81 srv := rpc.NewServer()
82 err := srv.Register(shrinker)
83 if err != nil {
84 log.Panicf("unable to register shrinker: %s", err)
85 }
86
87 sockname := backendSockname()
88 err = os.Remove(sockname)
89 if err != nil && !os.IsNotExist(err) {
90 log.Panicf("unable to unlink socket: %s", err)
91 }
92
93 lis, err := net.Listen("unix", sockname)
94 if err != nil {
95 log.Panicf("unable to register shrinker: %s", err)
96 }
97 for _, h := range backendhooks {
98 h()
99 }
100 srv.Accept(lis)
101}
102
103func startBackendServer() {
104 proc := exec.Command(os.Args[0], "-datadir", dataDir, "backend")
105 proc.Stdout = os.Stdout
106 proc.Stderr = os.Stderr
107 err := proc.Start()
108 if err != nil {
109 log.Panicf("can't exec backend: %s", err)
110 }
111}