veyron.io/wspr: Adding support for addName and removeName requests
to a server in wspr.

New IPC server API prohibits calling serve multiple times and instead
exposes addName and removeName to be used for publishing mutiple times.

This CL brings that functionality to wspr so that the JS API (separate CL)
can change to include addName and removeName as well.

Change-Id: If0d25008ae023521730b6dddfb8bce63f70d90aa
diff --git a/services/wsprd/app/app.go b/services/wsprd/app/app.go
index 1ac1363..9acd92b 100644
--- a/services/wsprd/app/app.go
+++ b/services/wsprd/app/app.go
@@ -73,12 +73,16 @@
 	IsStreaming bool
 }
 
-// A request javascript to serve undern a particular name
 type serveRequest struct {
 	Name     string
 	ServerId uint64
 }
 
+type addRemoveNameRequest struct {
+	Name     string
+	ServerId uint64
+}
+
 type jsonCaveatValidator struct {
 	Type string `json:"_type"`
 	Data json.RawMessage
@@ -566,6 +570,65 @@
 	}
 }
 
+// HandleAddNameRequest takes a request to add a new name to a server
+func (c *Controller) HandleAddNameRequest(data string, w lib.ClientWriter) {
+	var request addRemoveNameRequest
+	if err := json.Unmarshal([]byte(data), &request); err != nil {
+		w.Error(verror2.Convert(verror2.Internal, nil, err))
+		return
+	}
+
+	// Create a server for the websocket pipe, if it does not exist already
+	server, err := c.maybeCreateServer(request.ServerId)
+	if err != nil {
+		w.Error(verror2.Convert(verror2.Internal, nil, err))
+		return
+	}
+
+	// Add name
+	if err := server.AddName(request.Name); err != nil {
+		w.Error(verror2.Convert(verror2.Internal, nil, err))
+		return
+	}
+
+	// Send true to indicate request has finished without error
+	if err := w.Send(lib.ResponseFinal, true); err != nil {
+		w.Error(verror2.Convert(verror2.Internal, nil, err))
+		return
+	}
+}
+
+// HandleRemoveNameRequest takes a request to remove a name from a server
+func (c *Controller) HandleRemoveNameRequest(data string, w lib.ClientWriter) {
+	var request addRemoveNameRequest
+	if err := json.Unmarshal([]byte(data), &request); err != nil {
+		w.Error(verror2.Convert(verror2.Internal, nil, err))
+		return
+	}
+
+	// Create a server for the websocket pipe, if it does not exist already
+	server, err := c.maybeCreateServer(request.ServerId)
+	if err != nil {
+		w.Error(verror2.Convert(verror2.Internal, nil, err))
+		return
+	}
+
+	// Remove name
+	if err := server.RemoveName(request.Name); err != nil {
+		w.Error(verror2.Convert(verror2.Internal, nil, err))
+		return
+	}
+
+	// Remove name from signature cache as well
+	c.signatureManager.FlushCacheEntry(request.Name)
+
+	// Send true to indicate request has finished without error
+	if err := w.Send(lib.ResponseFinal, true); err != nil {
+		w.Error(verror2.Convert(verror2.Internal, nil, err))
+		return
+	}
+}
+
 // HandleServerResponse handles the completion of outstanding calls to JavaScript services
 // by filling the corresponding channel with the result from JavaScript.
 func (c *Controller) HandleServerResponse(id int64, data string) {
diff --git a/services/wsprd/app/messaging.go b/services/wsprd/app/messaging.go
index 58c35b6..f74034a 100644
--- a/services/wsprd/app/messaging.go
+++ b/services/wsprd/app/messaging.go
@@ -61,6 +61,12 @@
 
 	// A request to cancel an rpc initiated by the JS.
 	cancelMessage = 17
+
+	// A request to add a new name to server.
+	websocketAddName = 18
+
+	// A request to remove a name from server.
+	websocketRemoveName = 19
 )
 
 type Message struct {
@@ -89,6 +95,10 @@
 		go c.HandleServeRequest(msg.Data, w)
 	case stopServerMessage:
 		go c.HandleStopRequest(msg.Data, w)
+	case websocketAddName:
+		go c.HandleAddNameRequest(msg.Data, w)
+	case websocketRemoveName:
+		go c.HandleRemoveNameRequest(msg.Data, w)
 	case serverResponseMessage:
 		go c.HandleServerResponse(msg.Id, msg.Data)
 	case signatureRequestMessage:
diff --git a/services/wsprd/ipc/server/server.go b/services/wsprd/ipc/server/server.go
index 38b0e16..70bbfdc 100644
--- a/services/wsprd/ipc/server/server.go
+++ b/services/wsprd/ipc/server/server.go
@@ -391,3 +391,11 @@
 	s.outstandingServerRequests = make(map[int64]chan *serverRPCReply)
 	s.server.Stop()
 }
+
+func (s *Server) AddName(name string) error {
+	return s.server.AddName(name)
+}
+
+func (s *Server) RemoveName(name string) error {
+	return s.server.RemoveName(name)
+}
diff --git a/services/wsprd/lib/signature_manager.go b/services/wsprd/lib/signature_manager.go
index 1d38641..fa78195 100644
--- a/services/wsprd/lib/signature_manager.go
+++ b/services/wsprd/lib/signature_manager.go
@@ -10,6 +10,7 @@
 
 type SignatureManager interface {
 	Signature(ctx context.T, name string, client ipc.Client, opts ...ipc.CallOpt) (*ipc.ServiceSignature, error)
+	FlushCacheEntry(name string)
 }
 
 // signatureManager can be used to discover the signature of a remote service
@@ -43,7 +44,7 @@
 	return time.Now().Sub(c.lastAccessed) > ttl
 }
 
-// signature uses the given client to fetch the signature for the given service name.
+// Signature uses the given client to fetch the signature for the given service name.
 // It locks until it fetches the service signature from the remote server, if not a cache hit.
 func (sm *signatureManager) Signature(ctx context.T, name string, client ipc.Client, opts ...ipc.CallOpt) (*ipc.ServiceSignature, error) {
 	sm.Lock()
@@ -77,3 +78,8 @@
 
 	return &result, nil
 }
+
+// FlushCacheEntry removes the cached signature for the given name
+func (sm *signatureManager) FlushCacheEntry(name string) {
+	delete(sm.cache, name)
+}