I am using the Photoshop Connection SDK to get my iPad app connected to Photoshop.
(The SDK with all sample iOS projects can be downloaded here if you want to look closer: http://www.adobe.com/devnet/photoshop/sdk.html)
While I have it working, its hard for me to solve my issue as I don't entirely understand the networking between the iPad and Photoshop. So here is my issue:
NSString *s1 = [NSString stringWithUTF8String:"app.activeDocument.layers[0].name;"];
NSData *dataToSend = [s1 dataUsingEncoding:NSUTF8StringEncoding];
[self sendJavaScriptMessage:dataToSend];
artLayerName_transaction = transaction_id -1;
There is a little snippet of code, to send a message asking for the name of layer at index 0. That works great. However, let's say I try and send the same message straight after that but for index 1 as well.
Both messages are sent, but only one returns its string. The string is returned here:
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)streamEvent;
If you see the example projects its just the same, each message with its own transaction id as well. The method goes through a bunch of decrypting and things to receive that string and then reaches this:
NSString *string = [[NSString alloc] initWithBytes:received_data length:received_length encoding:NSUTF8StringEncoding];
if (content != 1)
{
if (transaction == artLayerName_transaction)
{
[self processLayerName:string];
needOutput = NO;
}
}
I've out the full method at the bottom for full analysing.
It checks that its receiving the specific message so I can then take the result (string, my layer name) and do what I like with it. However when I try and send more than one message with the same transaction id I only get one of the two results. In the code above, string gives me both my layer names, but the if statement is only called once.
Is there a known way around sending several messages at once? I have tried getting an array back rather than several strings without luck as well.
Apparently I need to modify the code to accept more then message. However I don't really understand the code well enough, so please also explain any of the principals behind it.
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)streamEvent
{
NSInputStream * istream;
switch(streamEvent)
{
case NSStreamEventHasBytesAvailable:;
UInt8 buffer[1024];
unsigned int actuallyRead = 0;
istream = (NSInputStream *)aStream;
if (!dataBuffer)
{
dataBuffer = [[NSMutableData alloc] initWithCapacity:2048];
}
actuallyRead = [istream read:buffer maxLength:1024];
[dataBuffer appendBytes:buffer length:actuallyRead];
// see if we have enough to process, loop over messages in buffer
while( YES )
{
// Did we read the header yet?
if ( packetBodySize == -1 )
{
// Do we have enough bytes in the buffer to read the header?
if ( [dataBuffer length] >= sizeof(int) ) {
// extract length
memcpy(&packetBodySize, [dataBuffer bytes], sizeof(int));
packetBodySize = ntohl( packetBodySize ); // size is in network byte order
// remove that chunk from buffer
NSRange rangeToDelete = {0, sizeof(int)};
[dataBuffer replaceBytesInRange:rangeToDelete withBytes:NULL length:0];
}
else {
// We don't have enough yet. Will wait for more data.
break;
}
}
// We should now have the header. Time to extract the body.
if ( [dataBuffer length] >= ((NSUInteger) packetBodySize) )
{
// We now have enough data to extract a meaningful packet.
const int kPrologLength = 16;
char *buffer = (char *)[dataBuffer bytes];
// if incoming message is color change, then don't display message
BOOL needOutput = YES;
// fetch the communication status
unsigned long com_status = *((unsigned long *)(buffer + 0));
com_status = ntohl( com_status );
// decrypt the message
size_t decryptedLength = (size_t) packetBodySize - 4; // don't include com status
int skip_message = 0;
if (com_status == 0 && sCryptorRef)
{
PSCryptorStatus decryptResult = EncryptDecrypt (sCryptorRef, false, buffer+4, decryptedLength, buffer+4, decryptedLength, &decryptedLength);
if (kCryptorSuccess != decryptResult)
{
// failed to decrypt. Ingore messageg and disconnect
skip_message = 1;
[self logMessage:@"ERROR: Decryption failed. Wrong password.\n" clearLine:NO];
}
}
else
{
if (com_status != 0)
[self logMessage:@"ERROR: Problem with communication, possible wrong password.\n" clearLine:NO];
if (!sCryptorRef)
[self logMessage:@"ERROR: Cryptor Ref is NULL, possible reason being that password was not supplied or password binding function failed.\n" clearLine:NO];
}
// Interpret encrypted section
if (!skip_message)
{
// version, 32 bit unsigned int, network byte order
unsigned long protocol_version = *((unsigned long *)(buffer + 4));
protocol_version = ntohl( protocol_version );
if (protocol_version != 1)
{
// either the message is corrupted or the protocol is newer.
[self logMessage:@"Incoming protocol version is different the expected. (or the message is corrupted.) Not processing.\n" clearLine:NO];
skip_message = 1;
}
if (!skip_message)
{
// transaction, 32 bit unsigned int, network byte order
unsigned long transaction = *((unsigned long *)(buffer + 8));
transaction = ntohl( transaction );
// content type, 32 bit unsigned int, network byte order
unsigned long content = *((unsigned long *)(buffer + 12));
content = ntohl( content );
unsigned char *received_data = (unsigned char *)(buffer+kPrologLength);
int received_length = (decryptedLength-(kPrologLength-4));
if (content == 3) // image data
{
// process image data
unsigned char image_type = *((unsigned char *)received_data);
[self logMessage:@"Incoming data is IMAGE. Skipping\n" clearLine:NO];
if (image_type == 1) // JPEG
{
[self logMessage:@"By the way, incoming image is JPEG\n" clearLine:NO];
}
else if (image_type == 2) // Pixmap
{
[self logMessage:@"By the way, incoming image is Pixmap\n" clearLine:NO];
}
else
{
[self logMessage:@"Unknown image type\n" clearLine:NO];
}
}
else
{
// Set the response string
NSString *string = [[NSString alloc] initWithBytes:received_data length:received_length encoding:NSUTF8StringEncoding];
//NSLog(@"string: %@\n id:%li", string, transaction);
// see if this is a response we're looking for
if (content != 1)
{
if (transaction == foregroundColor_subscription || transaction == foregroundColor_transaction)
{
[self processForegroundChange:string];
needOutput = NO;
}
if (transaction == backgroundColor_subscription || transaction == backgroundColor_transaction)
{
[self processBackgroundChange:string];
needOutput = NO;
}
if (transaction == tool_transaction)
{
[self processToolChange:string];
needOutput = NO;
}
if (transaction == artLayerName_transaction)
{
[self processLayerName:string];
needOutput = NO;
}
}
//Tells me about every event thats happened (spammy tech nonsence, no good for user log)
//if (needOutput) [self logMessage:string clearLine:NO];
}
}
}
// Remove that chunk from buffer
NSRange rangeToDelete = {0, packetBodySize};
[dataBuffer replaceBytesInRange:rangeToDelete withBytes:NULL length:0];
// We have processed the packet. Resetting the state.
packetBodySize = -1;
}
else
{
// Not enough data yet. Will wait.
break;
}
}
break;
case NSStreamEventEndEncountered:;
[self closeStreams];
[self logMessage:[NSString stringWithFormat: @"%@ End encountered, closing stream.\n", outputMessage.text] clearLine:NO];
break;
case NSStreamEventHasSpaceAvailable:
case NSStreamEventErrorOccurred:
case NSStreamEventOpenCompleted:
case NSStreamEventNone:
default:
break;
}
}
EDIT:
While this has worked, it has bumped me into another issue. I looked at the psconnection sample and saw what you were talking about, however I haven't been using the full framework but have it connect like in the other sample projects. I very simply increase my transaction id by 1 every time it comes to process a layer name such as in the code above.
Like this:
if (transaction == docName_transaction)
{
docName_transaction++;
[self processDocName:string];
}
This works for the most part, however if I do this to another transaction id at the same time I get overlap. Meaning I end up processing the result for one id at the wrong time. Say I am getting both the total number of docs and the name of each one.
So I have two if statements like above, but I end up processing the total docs in both if statements and I can't see how to atop this overlap. Its fairly important to be able to receive multiple messages at once.