couchbaselabs / BLIP-Cocoa

Implementation of the BLIP messaging protocol, for iOS and Mac OS X
Apache License 2.0
14 stars 8 forks source link

Questions on blip concepts in context of simple file transfer app #6

Open tleyden opened 6 years ago

tleyden commented 6 years ago

I started building a simple file transfer app to get my hands dirty with blip.

and then ClientB pushes it's data to the server, which then pushes it down to clientA.

The 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:

Does 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 that might give a more concrete idea of what I'm trying to do.

Also, 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.

@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!

tleyden commented 6 years ago

I found another way to do this which is a bit more async (and I'm guessing more idiomatic).

Client code

    context := blip.NewContext()
    sender, err := context.Dial(fmt.Sprintf("ws://localhost:%d/%s", DefaultPort, DefaultEndpoint), "http://localhost")
    if err != nil {
        panic("Error opening WebSocket: " + err.Error())
    }

    receivedFileWaitGroup := sync.WaitGroup{}

    // If the server sends any requests with more files, handle them here.
    context.HandlerForProfile[ProfileReceiveFile] = func(request *blip.Message) {

        defer receivedFileWaitGroup.Done()

        body, err := request.Body()
        if err != nil {
            response := request.Response()
            response.SetError("CloudDrop", 0, fmt.Sprintf("Error reading request body in profile handler: %v.  Error %v", ProfileListUsers, err))
            return
        }

        log.Printf("Client just received incoming request! %s", body)

        if response := request.Response(); response != nil {
            response.SetBody([]byte("Generic Response"))
            response.Properties["Content-Type"] = request.Properties["Content-Type"]
        }

    }

    request := blip.NewRequest()
    request.SetProfile(ProfileReceiveFile)
    request.Properties["Content-Type"] = "application/octet-stream"
    request.SetBody([]byte("username"))
    request.SetNoReply(true)

    sent := sender.Send(request)
    if !sent {
        panic(fmt.Sprintf("Could not send"))
    }

    receivedFileWaitGroup.Add(1)

    // block until we get a file
    receivedFileWaitGroup.Wait()

Server code

    blipContext.HandlerForProfile[ProfileReceiveFile] = func(request *blip.Message) {

        // The body contains the username
        body, err := request.Body()
        if err != nil {
            response := request.Response()
            response.SetError("CloudDrop", 0, fmt.Sprintf("Error reading username from request: %v", err))
            return
        }

                // Simulate another client connecting, getting a handle to the sender, and creating a new outbound request to send the data
        go func() {
            log.Printf("Waiting 10 seconds to send request2")
            time.Sleep(time.Second * 10)
            request2 := blip.NewRequest()
            request2.SetProfile(ProfileReceiveFile)
            request2.Properties["Content-Type"] = request.Properties["Content-Type"]
            request2.SetBody([]byte("request2 content"))
            sent := request.Sender.Send(request2)
            if !sent {
                panic(fmt.Sprintf("Could not send"))
            }
        }()