1
0
mirror of https://github.com/danog/Telegram.git synced 2024-12-12 09:29:55 +01:00
Telegram/Share/TGUploadMediaSignals.m

238 lines
11 KiB
Mathematica
Raw Normal View History

2015-10-01 18:19:52 +02:00
#import "TGUploadMediaSignals.h"
@implementation TGUploadMediaSignals
+ (SSignal *)uploadDataWithContext:(TGShareContext *)context data:(NSData *)data outFileId:(int64_t *)outFileId outLargeParts:(bool *)outLargeParts outNumberOfParts:(NSUInteger *)outNumberOfParts
{
int64_t fileId = 0;
arc4random_buf(&fileId, 8);
if (outFileId)
*outFileId = fileId;
NSUInteger partSize = 0;
if (data.length >= 10 * 1024 * 1024)
partSize = 512 * 1024;
else
partSize = 12 * 1024;
bool largeParts = partSize >= 500 * 1024;
if (outLargeParts)
*outLargeParts = largeParts;
NSUInteger numberOfParts = data.length / partSize + (data.length % partSize == 0 ? 0 : 1);
if (outNumberOfParts)
*outNumberOfParts = numberOfParts;
SSignal *uploadSignal = [[context connectionContextForDatacenter:context.mtProto.datacenterId] mapToSignal:^SSignal *(TGPooledDatacenterConnectionContext *datacenterContext)
{
return [[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber)
{
SDisposableSet *partsDisposables = [[SDisposableSet alloc] init];
NSMutableArray *partsSignals = [[NSMutableArray alloc] init];
for (NSUInteger i = 0; i < numberOfParts; i++)
{
SSignal *uploadPart = [[SSignal single:nil] mapToSignal:^SSignal *(__unused id next)
{
2016-02-25 01:03:51 +01:00
Api48_FunctionContext *functionContext = nil;
2015-10-01 18:19:52 +02:00
if (largeParts)
{
2016-02-25 01:03:51 +01:00
functionContext = [Api48 upload_saveBigFilePartWithFileId:@(fileId) filePart:@(i) fileTotalParts:@(numberOfParts) bytes:[data subdataWithRange:NSMakeRange(i * partSize, MIN(data.length - i * partSize, partSize))]];
2015-10-01 18:19:52 +02:00
}
else
{
2016-02-25 01:03:51 +01:00
functionContext = [Api48 upload_saveFilePartWithFileId:@(fileId) filePart:@(i) bytes:[data subdataWithRange:NSMakeRange(i * partSize, MIN(data.length - i * partSize, partSize))]];
2015-10-01 18:19:52 +02:00
}
return [[datacenterContext.context function:functionContext] map:^id(__unused id next)
{
return @((float)i / (float)numberOfParts);
}];
}];
[partsSignals addObject:uploadPart];
}
__block bool cancelled = false;
SAtomic *partsState = [[SAtomic alloc] initWithValue:@{@"remainingParts": partsSignals, @"uploadingParts": @(0)}];
__block void (^maybeTakeParts)() = nil;
void (^maybeTakePartsImpl)() = ^
{
if (cancelled)
return;
__block bool complete = false;
NSMutableArray *takenParts = [[NSMutableArray alloc] init];
[partsState modify:^id(NSDictionary *state)
{
if (((NSArray *)state[@"remainingParts"]).count == 0 && [state[@"uploadingParts"] intValue] <= 0)
{
complete = true;
}
else if (((NSArray *)state[@"remainingParts"]).count != 0 && [state[@"uploadingParts"] intValue] < 3)
{
NSMutableArray *remainingParts = [[NSMutableArray alloc] initWithArray:state[@"remainingParts"]];
for (int i = 0; i < 3 && remainingParts.count != 0; i++)
{
[takenParts addObject:remainingParts[0]];
[remainingParts removeObjectAtIndex:0];
}
return @{@"remainingParts": remainingParts, @"uploadingParts": @([state[@"uploadingParts"] intValue] + takenParts.count)};
}
return state;
}];
if (complete)
[subscriber putCompletion];
else if (takenParts.count != 0)
{
for (SSignal *uploadPart in takenParts)
{
id<SDisposable> disposable = [uploadPart startWithNext:^(id next)
{
[subscriber putNext:next];
} error:^(id error)
{
[subscriber putError:error];
} completed:^
{
[partsState modify:^id(NSDictionary *state)
{
return @{@"remainingParts": state[@"remainingParts"], @"uploadingParts": @([state[@"uploadingParts"] intValue] - 1)};
}];
maybeTakeParts();
}];
[partsDisposables add:disposable];
}
}
};
maybeTakeParts = [maybeTakePartsImpl copy];
[partsDisposables add:[[SBlockDisposable alloc] initWithBlock:^
{
cancelled = true;
}]];
maybeTakeParts();
return partsDisposables;
}];
/*SSignal *uploadPartsSignal = [SSignal complete];
for (NSUInteger i = 0; i < numberOfParts; i++)
{
SSignal *uploadPart = [[SSignal single:nil] mapToSignal:^SSignal *(__unused id next)
{
2016-02-25 01:03:51 +01:00
Api48_FunctionContext *functionContext = nil;
2015-10-01 18:19:52 +02:00
if (largeParts)
{
2016-02-25 01:03:51 +01:00
functionContext = [Api48 upload_saveBigFilePartWithFileId:@(fileId) filePart:@(i) fileTotalParts:@(numberOfParts) bytes:[data subdataWithRange:NSMakeRange(i * partSize, MIN(data.length - i * partSize, partSize))]];
2015-10-01 18:19:52 +02:00
}
else
{
2016-02-25 01:03:51 +01:00
functionContext = [Api48 upload_saveFilePartWithFileId:@(fileId) filePart:@(i) bytes:[data subdataWithRange:NSMakeRange(i * partSize, MIN(data.length - i * partSize, partSize))]];
2015-10-01 18:19:52 +02:00
}
return [[datacenterContext.context function:functionContext] map:^id(__unused id next)
{
return @((float)i / (float)numberOfParts);
}];
}];
uploadPartsSignal = [uploadPartsSignal then:uploadPart];
}
return uploadPartsSignal;*/
}];
return uploadSignal;
}
+ (SSignal *)uploadPhotoWithContext:(TGShareContext *)context data:(NSData *)data
{
int64_t fileId = 0;
bool largeParts = false;
NSUInteger numberOfParts = 0;
SSignal *uploadSignal = [self uploadDataWithContext:context data:data outFileId:&fileId outLargeParts:&largeParts outNumberOfParts:&numberOfParts];
2016-02-25 01:03:51 +01:00
Api48_InputFile *inputFile = nil;
2015-10-01 18:19:52 +02:00
if (largeParts)
2016-02-25 01:03:51 +01:00
inputFile = [Api48_InputFile inputFileBigWithPid:@(fileId) parts:@(numberOfParts) name:@"file.jpg"];
2015-10-01 18:19:52 +02:00
else
2016-02-25 01:03:51 +01:00
inputFile = [Api48_InputFile inputFileWithPid:@(fileId) parts:@(numberOfParts) name:@"file.jpg" md5Checksum:@""];
2015-10-01 18:19:52 +02:00
2016-02-25 01:03:51 +01:00
Api48_InputMedia_inputMediaUploadedPhoto *inputMedia = [Api48_InputMedia inputMediaUploadedPhotoWithFile:inputFile caption:@""];
2015-10-01 18:19:52 +02:00
uploadSignal = [uploadSignal then:[SSignal single:inputMedia]];
return uploadSignal;
}
+ (SSignal *)uploadFileWithContext:(TGShareContext *)context data:(NSData *)data name:(NSString *)name mimeType:(NSString *)mimeType attributes:(NSArray *)attributes
{
int64_t fileId = 0;
bool largeParts = false;
NSUInteger numberOfParts = 0;
SSignal *uploadSignal = [self uploadDataWithContext:context data:data outFileId:&fileId outLargeParts:&largeParts outNumberOfParts:&numberOfParts];
2016-02-25 01:03:51 +01:00
Api48_InputFile *inputFile = nil;
2015-10-01 18:19:52 +02:00
if (largeParts)
2016-02-25 01:03:51 +01:00
inputFile = [Api48_InputFile inputFileBigWithPid:@(fileId) parts:@(numberOfParts) name:name];
2015-10-01 18:19:52 +02:00
else
2016-02-25 01:03:51 +01:00
inputFile = [Api48_InputFile inputFileWithPid:@(fileId) parts:@(numberOfParts) name:name md5Checksum:@""];
2015-10-01 18:19:52 +02:00
NSMutableArray *completeAttributes = [[NSMutableArray alloc] init];
2016-02-25 01:03:51 +01:00
[completeAttributes addObject:[Api48_DocumentAttribute documentAttributeFilenameWithFileName:name]];
2015-10-01 18:19:52 +02:00
[completeAttributes addObjectsFromArray:attributes];
2016-02-25 01:03:51 +01:00
Api48_InputMedia_inputMediaUploadedDocument *inputMedia = [Api48_InputMedia inputMediaUploadedDocumentWithFile:inputFile mimeType:mimeType.length == 0 ? @"application/octet-stream" : mimeType attributes:completeAttributes caption:@""];
2015-10-01 18:19:52 +02:00
uploadSignal = [uploadSignal then:[SSignal single:inputMedia]];
return uploadSignal;
}
2016-02-25 01:03:51 +01:00
+ (SSignal *)uploadVideoWithContext:(TGShareContext *)context data:(NSData *)data thumbData:(NSData *)thumbData duration:(int32_t)duration width:(int32_t)width height:(int32_t)height mimeType:(NSString *)mimeType
{
int64_t fileId = 0;
bool largeParts = false;
NSUInteger numberOfParts = 0;
SSignal *uploadSignal = [self uploadDataWithContext:context data:data outFileId:&fileId outLargeParts:&largeParts outNumberOfParts:&numberOfParts];
NSString *fileName = @"file.mov";
Api48_InputFile *inputFile = nil;
if (largeParts)
inputFile = [Api48_InputFile inputFileBigWithPid:@(fileId) parts:@(numberOfParts) name:fileName];
else
inputFile = [Api48_InputFile inputFileWithPid:@(fileId) parts:@(numberOfParts) name:fileName md5Checksum:@""];
int64_t thumbFileId = 0;
bool thumbLargeParts = false;
NSUInteger thumbNumberOfParts = 0;
SSignal *thumbUploadSignal = [[self uploadDataWithContext:context data:thumbData outFileId:&thumbFileId outLargeParts:&thumbLargeParts outNumberOfParts:&thumbNumberOfParts] filter:^bool(id value)
{
return ![value isKindOfClass:[NSNumber class]];
}];
NSString *thumbFileName = @"file.jpg";
Api48_InputFile *inputThumbFile = nil;
if (thumbLargeParts)
inputThumbFile = [Api48_InputFile inputFileBigWithPid:@(thumbFileId) parts:@(thumbNumberOfParts) name:thumbFileName];
else
inputThumbFile = [Api48_InputFile inputFileWithPid:@(thumbFileId) parts:@(thumbNumberOfParts) name:thumbFileName md5Checksum:@""];
Api48_InputMedia_inputMediaUploadedThumbDocument *inputMedia = [Api48_InputMedia inputMediaUploadedThumbDocumentWithFile:inputFile thumb:inputThumbFile mimeType:@"video/mp4" attributes:@[
[Api48_DocumentAttribute documentAttributeVideoWithDuration:@(duration) w:@(width) h:@(height)],
[Api48_DocumentAttribute documentAttributeFilenameWithFileName:@"video.mp4"]
] caption:@""];
uploadSignal = [[uploadSignal then:thumbUploadSignal] then:[SSignal single:inputMedia]];
return uploadSignal;
}
2015-10-01 18:19:52 +02:00
@end