{"action":"created","issue":{"url":"https://api.github.com/repos/couchbaselabs/BLIP-Cocoa/issues/6","repository_url":"https://api.github.com/repos/couchbaselabs/BLIP-Cocoa","labels_url":"https://api.github.com/repos/couchbaselabs/BLIP-Cocoa/issues/6/labels{/name}","comments_url":"https://api.github.com/repos/couchbaselabs/BLIP-Cocoa/issues/6/comments","events_url":"https://api.github.com/repos/couchbaselabs/BLIP-Cocoa/issues/6/events","html_url":"https://github.com/couchbaselabs/BLIP-Cocoa/issues/6","id":270484809,"number":6,"title":"Questions on blip concepts in context of simple file transfer app","user":{"login":"tleyden","id":296876,"avatar_url":"https://avatars1.githubusercontent.com/u/296876?v=4","gravatar_id":"","url":"https://api.github.com/users/tleyden","html_url":"https://github.com/tleyden","followers_url":"https://api.github.com/users/tleyden/followers","following_url":"https://api.github.com/users/tleyden/following{/other_user}","gists_url":"https://api.github.com/users/tleyden/gists{/gist_id}","starred_url":"https://api.github.com/users/tleyden/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tleyden/subscriptions","organizations_url":"https://api.github.com/users/tleyden/orgs","repos_url":"https://api.github.com/users/tleyden/repos","events_url":"https://api.github.com/users/tleyden/events{/privacy}","received_events_url":"https://api.github.com/users/tleyden/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2017-11-01T23:24:15Z","updated_at":"2017-11-02T01:03:48Z","closed_at":null,"author_association":"NONE","body":"\r\nI started building a simple file transfer app to get my hands dirty with blip.  \r\n\r\n- There's a server component in the cloud, and two clients on different computers.\r\n- ClientA connects to the server and says \"I'm foo, and I'm ready to receive a file\"\r\n- ClientB connects to the server and says \"I want to send /tmp/file.txt to foo\"\r\n\r\nand then ClientB pushes it's data to the server, which then pushes it down to clientA.\r\n\r\nThe way I was planning on implementing it was to have the server do the following when receiving a request from ClientA stating they are ready to receive a file:\r\n\r\n- Add an entry for the receiver to a global map, which includes a channel\r\n- Wait for data to come in on the channel (from ClientB that wants to send)\r\n- When a sending client comes along (ClientB), find the receiver entry in the global map and then push all the data into the associated channel.\r\n- Read the data from the channel and send it on the response to the blocked/waiting ClientA\r\n\r\nDoes the server blocking the ClientA response until ClientB shows up to send the file sound like a  recommended way to do this?  How long can I block in a request handler before the sending client disconnects with a timeout?  Here is a [code snippet](https://github.com/tleyden/clouddrop/blob/bcf53f3d66cb99eee71dede0777f25df5ad7c34b/pkg/clouddrop/server.go#L48-L88) that might give a more concrete idea of what I'm trying to do.\r\n\r\nAlso, how would I do this in a streaming fashion?  For example, I see a `func (m *Message) BodyReader() (io.Reader, error)` method, but no equivalent streaming API for the response.  I only see see `func (m *Message) SetBody(body []byte)` which expects the entire body to be in memory.\r\n\r\n@snej Btw if there's a better place to ask these kinds of questions (forum?  google group?), let me know.  I just wanted it out of email so I can go find it later, and maybe get other blip experts to chime in!\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/couchbaselabs/BLIP-Cocoa/issues/comments/341287983","html_url":"https://github.com/couchbaselabs/BLIP-Cocoa/issues/6#issuecomment-341287983","issue_url":"https://api.github.com/repos/couchbaselabs/BLIP-Cocoa/issues/6","id":341287983,"user":{"login":"tleyden","id":296876,"avatar_url":"https://avatars1.githubusercontent.com/u/296876?v=4","gravatar_id":"","url":"https://api.github.com/users/tleyden","html_url":"https://github.com/tleyden","followers_url":"https://api.github.com/users/tleyden/followers","following_url":"https://api.github.com/users/tleyden/following{/other_user}","gists_url":"https://api.github.com/users/tleyden/gists{/gist_id}","starred_url":"https://api.github.com/users/tleyden/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tleyden/subscriptions","organizations_url":"https://api.github.com/users/tleyden/orgs","repos_url":"https://api.github.com/users/tleyden/repos","events_url":"https://api.github.com/users/tleyden/events{/privacy}","received_events_url":"https://api.github.com/users/tleyden/received_events","type":"User","site_admin":false},"created_at":"2017-11-02T01:03:48Z","updated_at":"2017-11-02T01:03:48Z","author_association":"NONE","body":"I found another way to do this which is a bit more async (and I'm guessing more idiomatic).\r\n\r\n- The client it tells the server it wants to receive a file by sending a request with `SetNoReply(true)`:\r\n- The client registers a profile handler that the server will use to send files\r\n- It blocks until it gets a file -- tracked by `receivedFileWaitGroup` \r\n\r\n## Client code\r\n\r\n```\r\n\tcontext := blip.NewContext()\r\n\tsender, err := context.Dial(fmt.Sprintf(\"ws://localhost:%d/%s\", DefaultPort, DefaultEndpoint), \"http://localhost\")\r\n\tif err != nil {\r\n\t\tpanic(\"Error opening WebSocket: \" + err.Error())\r\n\t}\r\n\r\n\treceivedFileWaitGroup := sync.WaitGroup{}\r\n\r\n\t// If the server sends any requests with more files, handle them here.\r\n\tcontext.HandlerForProfile[ProfileReceiveFile] = func(request *blip.Message) {\r\n\r\n\t\tdefer receivedFileWaitGroup.Done()\r\n\r\n\t\tbody, err := request.Body()\r\n\t\tif err != nil {\r\n\t\t\tresponse := request.Response()\r\n\t\t\tresponse.SetError(\"CloudDrop\", 0, fmt.Sprintf(\"Error reading request body in profile handler: %v.  Error %v\", ProfileListUsers, err))\r\n\t\t\treturn\r\n\t\t}\r\n\r\n\t\tlog.Printf(\"Client just received incoming request! %s\", body)\r\n\r\n\t\tif response := request.Response(); response != nil {\r\n\t\t\tresponse.SetBody([]byte(\"Generic Response\"))\r\n\t\t\tresponse.Properties[\"Content-Type\"] = request.Properties[\"Content-Type\"]\r\n\t\t}\r\n\r\n\t}\r\n\r\n\trequest := blip.NewRequest()\r\n\trequest.SetProfile(ProfileReceiveFile)\r\n\trequest.Properties[\"Content-Type\"] = \"application/octet-stream\"\r\n\trequest.SetBody([]byte(\"username\"))\r\n\trequest.SetNoReply(true)\r\n\r\n\tsent := sender.Send(request)\r\n\tif !sent {\r\n\t\tpanic(fmt.Sprintf(\"Could not send\"))\r\n\t}\r\n\r\n\treceivedFileWaitGroup.Add(1)\r\n\r\n\t// block until we get a file\r\n\treceivedFileWaitGroup.Wait()\r\n```\r\n\r\n## Server code\r\n\r\n```\r\n\tblipContext.HandlerForProfile[ProfileReceiveFile] = func(request *blip.Message) {\r\n\r\n\t\t// The body contains the username\r\n\t\tbody, err := request.Body()\r\n\t\tif err != nil {\r\n\t\t\tresponse := request.Response()\r\n\t\t\tresponse.SetError(\"CloudDrop\", 0, fmt.Sprintf(\"Error reading username from request: %v\", err))\r\n\t\t\treturn\r\n\t\t}\r\n\r\n                // Simulate another client connecting, getting a handle to the sender, and creating a new outbound request to send the data\r\n\t\tgo func() {\r\n\t\t\tlog.Printf(\"Waiting 10 seconds to send request2\")\r\n\t\t\ttime.Sleep(time.Second * 10)\r\n\t\t\trequest2 := blip.NewRequest()\r\n\t\t\trequest2.SetProfile(ProfileReceiveFile)\r\n\t\t\trequest2.Properties[\"Content-Type\"] = request.Properties[\"Content-Type\"]\r\n\t\t\trequest2.SetBody([]byte(\"request2 content\"))\r\n\t\t\tsent := request.Sender.Send(request2)\r\n\t\t\tif !sent {\r\n\t\t\t\tpanic(fmt.Sprintf(\"Could not send\"))\r\n\t\t\t}\r\n\t\t}()\r\n```"}}
{"actor":{"display_login":"tleyden"}}