Как обслуживать удаленный файл (взятый с удаленного 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
,