Как обслуживать удаленный файл (взятый с удаленного SMB-сервера) на определенные запросы

Я пытаюсь предоставить видеофайл в качестве ответа, когда определенный запрос попадает на сервер (сервер работает в мобильном приложении). Например: кто-то заходит на http://mylocalip:8080/video, и я хочу показать ему видео.

Этот видеофайл может храниться локально или может быть внешним. Я начал пытаться обслуживать файл, расположенный на SMB-сервере, поэтому я попытался использовать этот код, чтобы получить файл с сервера и вернуть его (я знаю, что он ожидает чтения всего файла вместо чтения и отправки кусков, но должен работать право?):

webServer.addDefaultHandlerForMethod("GET", requestClass: GCDWebServerRequest.self, processBlock: {request in
            print("########\n########Request: \(request)")
            let webrequested:GCDWebServerRequest = request;
            let urlcita:String = String(webrequested.URL)
            print("URL of requests\(urlcita)")
            if urlcita.rangeOfString("videosmb") != nil{
                print("It's a video SMB request")

                //Test fake SMB file predefined. Read File using KxSMB

                let route:String = "smb://192.168.1.205/ServidorAH/video.avi";
                let extensFile:NSString = (route as NSString).pathExtension
                let contentype = GCDWebServerGetMimeTypeForExtension(extensFile as String);
                print("Content type MIME \(contentype)")


                //Open SMB file using KxSMB
                let authcredentials = KxSMBAuth.smbAuthWorkgroup("", username: "Guest", password: "");
                let provider = KxSMBProvider.sharedSmbProvider()!
                let archivoes = provider.fetchAtPath(route, auth: authcredentials)

                //Switch to manually end the reading when switched to true. In the future will send chunks of data until the end, instead of reading the whole file first.
                var interruptor:Bool = false

                //Response Stream block
                let responseStream: GCDWebServerStreamedResponse = GCDWebServerStreamedResponse(contentType: contentype, asyncStreamBlock: { completionBlock in

                    if (interruptor == true)
                    {
                        print("Test: End of reading")
                        completionBlock(NSData(), nil);
                    }

                    if archivoes!.isKindOfClass(NSError){
                        //It can not find the file, SMB error, so empty NSDATA to completion block
                        let errorcito:NSError = archivoes as! NSError
                        print("Error obteniendo archivo SMB: \(errorcito.localizedDescription)");
                        completionBlock(NSData(), nil);
                    }else{
                        print("Archivo SMB adecuado \(archivoes)")
                        let datos:NSData = archivoes!.readDataToEndOfFile()
                        //Print lenght of data (to check the size of the file)
                        print("Data lenght \(datos.length)")
                        //Set switch to true, so the next call will send an empty daya completion block
                        interruptor = true
                        //Send data chunk (in this case everything)
                        completionBlock(datos, nil);
                    }

                })
                return responseStream


            }else{
                //Default response
                return GCDWebServerDataResponse(HTML:"<html><body><p>Hello World<br></p></body></html>")
 }

Тем не менее, я не могу заставить его работать. Я всегда получаю сообщение об ошибке сломанного канала, и веб-плеер, обращающийся к веб-серверу (в том числе из Mac и iOS), ничего не воспроизводит. Я также попытался использовать встроенный проигрыватель iOS для записи ответа (KxMovie). Я получаю что-то вроде этого:

[DEBUG] Did open connection on socket 19
[DEBUG] Connection received 177 bytes on socket 19
[DEBUG] Connection on socket 19 preflighting request "GET /videosmb" with 177 bytes body
[DEBUG] Connection on socket 19 processing request "GET /videosmb" with 177 bytes body
[DEBUG] Did connect
[DEBUG] Did start background task
[DEBUG] Connection sent 175 bytes on socket 19
...

Используя локальный проигрыватель (KxMovie) из приложения, здесь, кажется, читаются заголовки файлов, и он получает правильный размер файла и размеры видео. Однако он не воспроизводится и заканчивается сообщением, что достиг конца видео (без воспроизведения). Сразу после этого WebServer показывает ошибку:

...       

[ERROR] Error while writing to socket 19: Broken pipe (32)
[DEBUG] Did close connection on socket 19
[VERBOSE] [fe80::cd0:28cd:3a37:b871%en1:8080] fe80::cd0:28cd:3a37:b871%en1:50109 200 "GET /videosmb" (177 | 175)
[DEBUG] Did disconnect
[DEBUG] Did end background task

Учитывая тот факт, что я впервые имею дело с SMB-серверами, я подумал, что, возможно, я что-то не так делал с SMB-частью, поэтому я решил использовать упрощенный метод только для тестирования. На этот раз я попытался обслужить простой файл mp4, хранящийся на удаленном веб-сервере (не SMB). Это тоже не сработало. Наконец, я попытался обслужить локальный файл, включенный в основной комплект приложения, и случилось то же самое: ничего. Вот код:

webServer.addDefaultHandlerForMethod("GET", requestClass: GCDWebServerRequest.self, processBlock: {request in
       print("########\n########Request: \(request)")
       let webrequested:GCDWebServerRequest = request;
       let url:String = String(webrequested.URL)
       print("URL of request: \(url)")
       if url.rangeOfString("video") != nil{
            print("It's a video request")

            let rutalocalita = (NSBundle.mainBundle()).pathForResource("video", ofType: "avi")
            let datos = NSData(contentsOfFile: rutalocalita!)!
            print("video size: \(datos.length)")
            return GCDWebServerDataResponse(data: datos, contentType: "video/avi")

        }else{
           //Default Response: Simple web
           return GCDWebServerDataResponse(HTML:"<html><body><p>Hello World<br></p></body></html>")
        }
})

Вот как выглядит журнал:

[DEBUG] Did open connection on socket 19
[DEBUG] Connection received 177 bytes on socket 19
[DEBUG] Connection on socket 19 preflighting request "GET /video" with 177 bytes body
[DEBUG] Connection on socket 19 processing request "GET /video" with 177 bytes body
[DEBUG] Did connect
[DEBUG] Did start background task
[myCUSTOMDebug] Read 13584902 b. I'm going to send the response back to the request.
[DEBUG] Connection sent 173 bytes on socket 19
...

Здесь локальная игра, которую я использую внутри приложения для отслеживания ответа, может читать такие вещи, как:

header='HTTP/1.1 200 OK'
2015-10-17 17:51:41.571 videotvtest[262:14252] http_code=200
2015-10-17 17:51:41.571 videotvtest[262:14252] header='Cache-Control: no-cache'
2015-10-17 17:51:41.571 videotvtest[262:14252] header='Content-Length: 13584902'
2015-10-17 17:51:41.572 videotvtest[262:14252] header='Content-Type: video/avi'
2015-10-17 17:51:41.572 videotvtest[262:14252] header='Connection: Close'
2015-10-17 17:51:41.573 videotvtest[262:14252] header='Server: GCDWebServer'

...
[ERROR] Error while writing to socket 19: Broken pipe (32)
[DEBUG] Did close connection on socket 19
[VERBOSE] [fe80::cd0:28cd:3a37:b871%en1:8080] fe80::cd0:28cd:3a37:b871%en1:50155 200 "GET /video" (177 | 173)
netbios_ns_send_name_query, name query sent for '*'.
[DEBUG] Did disconnect
[DEBUG] Did end background task

Я играю с tvOS и Xcode 7 для этого, но я думаю, что все будет в порядке, если я смогу показать обычный ответ HTML... так что я уверен, что что-то упустил, или, возможно, я пропустил некоторые рамки при установке WebServer (я не использую стручки)? заранее спасибо

1 ответ

Если вы хотите предоставить видеофайл, который может воспроизводиться в браузере с использованием тега video, по крайней мере в Chrome и Safari, вам необходимо реализовать запросы диапазона HTTP.

GCDWebServer автоматически реализует поддержку диапазона, если вы используете GCDWebServerFileResponse, Если вы используете другой тип ответа, вам нужно будет реализовать его самостоятельно, основываясь на byteRange собственность входящего GCDWebServerRequest, Вы должны скопировать и вставить логику из GCDWebServerFileResponse.m,

Другие вопросы по тегам