func (s *Server) GetNumClients() int {
	logger.AddTime(s.latency * 2)
	return len(s.keyHalves)
}
GetNumClients returns the number of clients for this server.
package server
import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/gob"
	"fmt"
	"io/ioutil"
	"math"
	"os"
	"path"
	"search/prototype/index"
	"search/prototype/logger"
	"search/prototype/searcher"
	"search/prototype/util"
	"strconv"
	"time"
)
type Server struct {
	directory string         
	lenMS     int            
	keyHalves [][]byte       
	salts     [][]byte       
	numFiles  int            
	size      uint64         
	latency   time.Duration  
	bandwidth int            
}
func CreateServer(numClients, lenMS, lenSalt int, directory string, fpRate float64, numUniqWords uint64) (s *Server, err error) {
	s = new(Server)
	masterSecret := make([]byte, lenMS)
	rand.Read(masterSecret)
	s.keyHalves = make([][]byte, numClients)
	s.lenMS = lenMS
	for i := 0; i < numClients; i++ {
		h := sha256.New()
		h.Write([]byte(strconv.Itoa(i)))
		cksum := h.Sum(nil)
		s.keyHalves[i] = util.XorBytes(masterSecret, cksum, lenMS)
	}
	r := int(math.Ceil(-math.Log2(fpRate)))
	s.size = uint64(math.Ceil(float64(numUniqWords) * float64(r) / math.Log(2)))
	s.salts, err = util.GenerateSalts(r, lenSalt)
	if err != nil {
		return
	}
	s.numFiles = 0
	s.directory = directory
	s.writeToFile()
	return
}
func CreateServerWithNetConfig(numClients, lenMS, lenSalt int, directory string, fpRate float64, numUniqWords uint64, latency time.Duration, bandwidth int) (*Server, error) {
	s, err := CreateServer(numClients, lenMS, lenSalt, directory, fpRate, numUniqWords)
	s.latency = latency
	s.bandwidth = bandwidth
	s.writeToFile()
	return s, err
}
func LoadServer(directory string) *Server {
	input, err := os.Open(path.Join(directory, "serverMD"))
	if err != nil {
		panic("Server metadata not found")
	}
	dec := gob.NewDecoder(input)
	s := new(Server)
	dec.Decode(&s.directory)
	dec.Decode(&s.numFiles)
	dec.Decode(&s.salts)
	dec.Decode(&s.keyHalves)
	dec.Decode(&s.lenMS)
	dec.Decode(&s.size)
	dec.Decode(&s.latency)
	dec.Decode(&s.bandwidth)
	input.Close()
	return s
}
func (s *Server) writeToFile() {
	file, _ := os.Create(path.Join(s.directory, "serverMD"))
	enc := gob.NewEncoder(file)
	enc.Encode(s.directory)
	enc.Encode(s.numFiles)
	enc.Encode(s.salts)
	enc.Encode(s.keyHalves)
	enc.Encode(s.lenMS)
	enc.Encode(s.size)
	enc.Encode(s.latency)
	enc.Encode(s.bandwidth)
	file.Close()
}
func (s *Server) AddFile(content []byte) (int, error) {
	logger.AddTime(s.latency * 2)
	logger.AddTime(time.Millisecond * time.Duration(float64(len(content))*1.5*8*1000/float64(s.bandwidth)))
	output, err := os.Create(path.Join(s.directory, strconv.Itoa(s.numFiles)))
	if err != nil {
		return 0, err
	}
	output.Write(content)
	s.numFiles++
	output.Close()
	s.writeToFile()
	return s.numFiles - 1, nil
}
func (s *Server) GetFile(docID int) ([]byte, error) {
	logger.AddTime(s.latency * 2)
	content, err := ioutil.ReadFile(path.Join(s.directory, strconv.Itoa(docID)))
	if err != nil {
		return nil, err
	}
	logger.AddTime(time.Millisecond * time.Duration(float64(len(content))*1.5*8*1000/float64(s.bandwidth)))
	return content, nil
}
func (s *Server) WriteIndex(si index.SecureIndex) error {
	logger.AddTime(s.latency * 2)
	output, err := si.MarshalBinary()
	if err != nil {
		return err
	}
	logger.AddTime(time.Millisecond * time.Duration(float64(len(output))*8*1000/float64(s.bandwidth)))
	file, err := os.Create(path.Join(s.directory, strconv.Itoa(si.DocID)+".index"))
	if err != nil {
		return err
	}
	file.Write(output)
	file.Close()
	return nil
}
func (s *Server) readIndex(docID int) (si index.SecureIndex, err error) {
	input, err := ioutil.ReadFile(path.Join(s.directory, strconv.Itoa(docID)+".index"))
	if err != nil {
		return
	}
	err = si.UnmarshalBinary(input)
	return
}
func (s *Server) SearchWord(trapdoors [][]byte) []int {
	logger.AddTime(s.latency * 2)
	var result []int
	for i := 0; i < s.numFiles; i++ {
		si, err := s.readIndex(i)
		if err != nil {
			continue
		}
		if searcher.SearchSecureIndex(si, trapdoors) {
			result = append(result, i)
		}
	}
	logger.AddTime(time.Millisecond * time.Duration(float64(len(trapdoors)*len(trapdoors[0])+len(result))*8*1000/float64(s.bandwidth)))
	return result
}
func (s *Server) WriteLookupTable(content []byte) {
	logger.AddTime(s.latency * 2)
	logger.AddTime(time.Millisecond * time.Duration(float64(len(content))*1.5*8*1000/float64(s.bandwidth)))
	file, _ := os.Create(path.Join(s.directory, "lookupTable"))
	file.Write(content)
	file.Close()
}
func (s *Server) ReadLookupTable() ([]byte, bool) {
	logger.AddTime(s.latency * 2)
	if _, err := os.Stat(path.Join(s.directory, "lookupTable")); os.IsNotExist(err) {
		return []byte{}, false
	}
	content, _ := ioutil.ReadFile(path.Join(s.directory, "lookupTable"))
	logger.AddTime(time.Millisecond * time.Duration(float64(len(content))*1.5*8*1000/float64(s.bandwidth)))
	return content, true
}