157
package main
import (
"bytes"
"encoding/json"
"github.com/asdine/storm"
"github.com/asdine/storm/q"
"go.etcd.io/bbolt"
"net"
"os"
"os/signal"
)
func DB() error {
bb, err := storm.Open(DBPATH, storm.BoltOptions(0600, nil))
if err != nil {
return err
}
var e EmailMeta
err = bb.Init(&e)
if err != nil {
return err
}
err = bb.Bolt.Update(func(tx *bbolt.Tx) error {
_, err = tx.CreateBucketIfNotExists([]byte("data"))
return err
})
if err != nil {
return err
}
db = bb
return nil
}
var db *storm.DB
func Listen() {
err := DB()
FtlLog(err)
_ = os.Remove(SOCK)
var sock *net.UnixListener
sock, err = net.ListenUnix("unix", &net.UnixAddr{SOCK, "socket"})
FtlLog(err)
// handle signals
go func() {
chn := make(chan os.Signal, 1)
signal.Notify(chn, os.Kill, os.Interrupt)
<-chn
db.Close()
sock.Close()
os.Remove(SOCK)
FtlLog(err)
os.Exit(0)
}()
var conn *net.UnixConn
for {
conn, err = sock.AcceptUnix()
if err != nil {
continue
}
go Handle(conn)
}
}
type Req struct {
CMD string `json:"CMD"`
Data []byte `json:"Data"`
}
func sendToSock(req Req) []byte {
var conn *net.UnixConn
var err error
conn, err = net.DialUnix("unix", &net.UnixAddr{
Name: SOCK,
Net: "local",
}, &net.UnixAddr{Name: SOCK, Net: "socket"})
FtlLog(err)
b, err := json.Marshal(req)
FtlLog(err)
var n int
conn.WriteTo(b, &net.UnixAddr{Name: SOCK, Net: "socket"})
n, err = conn.Write(b)
FtlLog(err)
println(n)
conn.ReadFrom(b)
return b
}
func Search(req Req) []byte {
var err error
var search string
if err = json.Unmarshal(req.Data, &search); err != nil {
return []byte("error unmarshalling request")
}
println(search)
search += "*"
var emails []EmailMeta
query := db.Select(q.Or(q.Re("Subject", search), q.Re("From", search), q.Re("To", search)))
_ = query.Find(&emails)
var b []byte
b, _ = json.Marshal(emails)
return b
}
func Handle(conn *net.UnixConn) {
var b bytes.Buffer
var buf = make([]byte, 1024)
var n int
var err error
for {
buf = make([]byte, 1024)
n, err = conn.Read(buf)
if err != nil || n == 0 {
break
}
b.Write(buf[:n])
}
var req Req
err = json.Unmarshal(b.Bytes(), &req)
if err != nil {
return
}
var bb []byte
switch req.CMD {
case "SEARCH":
bb = Search(req)
break
case "PUT":
bb = Put(req)
break
}
n, err = conn.Write(bb)
if err != nil {
return
}
println(n)
conn.Close()
}
type PUT struct {
M EmailMeta `json:"M"`
D []byte `json:"D"`
}
func Put(req Req) []byte {
var put PUT
if json.Unmarshal(req.Data, &put) != nil {
return []byte("ERR")
}
db.Save(&put.M)
db.Update(func(tx *bbolt.Tx) error {
return tx.Bucket([]byte("data")).Put(put.M.Id, put.D)
})
return []byte("OK")
}