sophuwu.site > mailboxxer   
              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")
}