Skip to content

Commit e3eac02

Browse files
committed
Added example applications
1 parent 1337626 commit e3eac02

30 files changed

+4903
-0
lines changed

Peertalk Example/Icon-1024.psd

442 KB
Binary file not shown.

Peertalk Example/Icon.icns

147 KB
Binary file not shown.

Peertalk Example/PTAppDelegate.h

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#import "PTChannel.h"
2+
3+
static const NSTimeInterval PTAppReconnectDelay = 1.0;
4+
5+
@interface PTAppDelegate : NSObject <NSApplicationDelegate, PTChannelDelegate>
6+
7+
@property (assign) IBOutlet NSWindow *window;
8+
@property (assign) IBOutlet NSTextField *inputTextField;
9+
@property (assign) IBOutlet NSTextView *outputTextView;
10+
11+
- (IBAction)sendMessage:(id)sender;
12+
13+
@end

Peertalk Example/PTAppDelegate.m

+293
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
#import "PTAppDelegate.h"
2+
#import "PTUSBHub.h"
3+
#import "PTExampleProtocol.h"
4+
#import <QuartzCore/QuartzCore.h>
5+
6+
@interface PTAppDelegate () {
7+
// If the remote connection is over USB transport...
8+
NSNumber *connectingToDeviceID_;
9+
NSNumber *connectedDeviceID_;
10+
NSDictionary *connectedDeviceProperties_;
11+
NSDictionary *remoteDeviceInfo_;
12+
dispatch_queue_t notConnectedQueue_;
13+
BOOL notConnectedQueueSuspended_;
14+
PTChannel *connectedChannel_;
15+
NSDictionary *consoleTextAttributes_;
16+
NSDictionary *consoleStatusTextAttributes_;
17+
}
18+
19+
@property (readonly) NSNumber *connectedDeviceID;
20+
@property PTChannel *connectedChannel;
21+
22+
- (void)presentMessage:(NSString*)message isStatus:(BOOL)isStatus;
23+
- (void)startListeningForDevices;
24+
- (void)didDisconnectFromDevice:(NSNumber*)deviceID;
25+
- (void)disconnectFromCurrentChannel;
26+
- (void)enqueueConnectToLocalIPv4Port;
27+
- (void)connectToLocalIPv4Port;
28+
- (void)connectToUSBDevice;
29+
30+
@end
31+
32+
33+
@implementation PTAppDelegate
34+
35+
@synthesize window = window_;
36+
@synthesize inputTextField = inputTextField_;
37+
@synthesize outputTextView = outputTextView_;
38+
@synthesize connectedDeviceID = connectedDeviceID_;
39+
40+
41+
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
42+
// We use a serial queue that we toggle depending on if we are connected or
43+
// not. When we are not connected to a peer, the queue is running to handle
44+
// "connect" tries. When we are connected to a peer, the queue is suspended
45+
// thus no longer trying to connect.
46+
notConnectedQueue_ = dispatch_queue_create("PTExample.notConnectedQueue", DISPATCH_QUEUE_SERIAL);
47+
48+
// Configure the output NSTextView we use for UI feedback
49+
outputTextView_.textContainerInset = NSMakeSize(15.0, 10.0);
50+
consoleTextAttributes_ = [NSDictionary dictionaryWithObjectsAndKeys:
51+
[NSFont fontWithName:@"helvetica" size:16.0], NSFontAttributeName,
52+
[NSColor lightGrayColor], NSForegroundColorAttributeName,
53+
nil];
54+
consoleStatusTextAttributes_ = [NSDictionary dictionaryWithObjectsAndKeys:
55+
[NSFont fontWithName:@"menlo" size:11.0], NSFontAttributeName,
56+
[NSColor darkGrayColor], NSForegroundColorAttributeName,
57+
nil];
58+
59+
// Configure the input NSTextField we use for UI input
60+
[inputTextField_ setFont:[NSFont fontWithDescriptor:[[consoleTextAttributes_ objectForKey:NSFontAttributeName] fontDescriptor] size:14.0]];
61+
[self.window makeFirstResponder:inputTextField_];
62+
63+
// Start listening for device attached/detached notifications
64+
[self startListeningForDevices];
65+
66+
// Start trying to connect to local IPv4 port (defined in PTExampleProtocol.h)
67+
[self enqueueConnectToLocalIPv4Port];
68+
69+
// Put a little message in the UI
70+
[self presentMessage:@"Ready for action — connecting at will." isStatus:YES];
71+
}
72+
73+
74+
- (IBAction)sendMessage:(id)sender {
75+
if (connectedChannel_) {
76+
NSString *message = self.inputTextField.stringValue;
77+
dispatch_data_t payload = [[message dataUsingEncoding:NSUTF8StringEncoding] createReferencingDispatchData];
78+
[connectedChannel_ sendFrameOfType:PTExampleFrameTypeTextMessage tag:PTFrameNoTag withPayload:payload callback:^(NSError *error) {
79+
if (error) {
80+
NSLog(@"Failed to send message: %@", error);
81+
}
82+
}];
83+
[self presentMessage:[NSString stringWithFormat:@"[you]: %@", message] isStatus:NO];
84+
self.inputTextField.stringValue = @"";
85+
}
86+
}
87+
88+
89+
- (void)presentMessage:(NSString*)message isStatus:(BOOL)isStatus {
90+
NSLog(@">> %@", message);
91+
[self.outputTextView.textStorage beginEditing];
92+
if (self.outputTextView.textStorage.length > 0) {
93+
message = [@"\n" stringByAppendingString:message];
94+
}
95+
[self.outputTextView.textStorage appendAttributedString:[[NSAttributedString alloc] initWithString:message attributes:isStatus ? consoleStatusTextAttributes_ : consoleTextAttributes_]];
96+
[self.outputTextView.textStorage endEditing];
97+
98+
[NSAnimationContext beginGrouping];
99+
[NSAnimationContext currentContext].duration = 0.15;
100+
[NSAnimationContext currentContext].timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
101+
NSClipView* clipView = [[self.outputTextView enclosingScrollView] contentView];
102+
NSPoint newOrigin = clipView.bounds.origin;
103+
newOrigin.y += 5.0; // hack A 1/2
104+
[clipView setBoundsOrigin:newOrigin]; // hack A 2/2
105+
newOrigin.y += 1000.0;
106+
newOrigin = [clipView constrainScrollPoint:newOrigin];
107+
[clipView.animator setBoundsOrigin:newOrigin];
108+
[NSAnimationContext endGrouping];
109+
110+
// Scrolling w/o animation:
111+
//[self.outputTextView scrollToEndOfDocument:self];
112+
}
113+
114+
115+
- (PTChannel*)connectedChannel {
116+
return connectedChannel_;
117+
}
118+
119+
- (void)setConnectedChannel:(PTChannel*)connectedChannel {
120+
connectedChannel_ = connectedChannel;
121+
122+
// Toggle the notConnectedQueue_ depending on if we are connected or not
123+
if (!connectedChannel_ && notConnectedQueueSuspended_) {
124+
dispatch_resume(notConnectedQueue_);
125+
notConnectedQueueSuspended_ = NO;
126+
} else if (connectedChannel_ && !notConnectedQueueSuspended_) {
127+
dispatch_suspend(notConnectedQueue_);
128+
notConnectedQueueSuspended_ = YES;
129+
}
130+
131+
if (!connectedChannel_ && connectingToDeviceID_) {
132+
[self enqueueConnectToUSBDevice];
133+
}
134+
}
135+
136+
137+
#pragma mark - PTChannelDelegate
138+
139+
140+
- (BOOL)ioFrameChannel:(PTChannel*)channel shouldAcceptFrameOfType:(uint32_t)type tag:(uint32_t)tag payloadSize:(uint32_t)payloadSize {
141+
if ( type != PTExampleFrameTypeDeviceInfo
142+
&& type != PTExampleFrameTypeTextMessage
143+
&& type != PTFrameTypeEndOfStream) {
144+
NSLog(@"Unexpected frame of type %u", type);
145+
[channel close];
146+
return NO;
147+
} else {
148+
return YES;
149+
}
150+
}
151+
152+
- (void)ioFrameChannel:(PTChannel*)channel didReceiveFrameOfType:(uint32_t)type tag:(uint32_t)tag payload:(PTData*)payload {
153+
//NSLog(@"received %@, %u, %u, %@", channel, type, tag, payload);
154+
if (type == PTExampleFrameTypeDeviceInfo) {
155+
NSDictionary *deviceInfo = [NSDictionary dictionaryWithContentsOfDispatchData:payload.dispatchData];
156+
[self presentMessage:[NSString stringWithFormat:@"Connected to %@", deviceInfo.description] isStatus:YES];
157+
} else if (type == PTExampleFrameTypeTextMessage) {
158+
NSString *message = [[NSString alloc] initWithBytes:payload.data length:payload.length encoding:NSUTF8StringEncoding];
159+
[self presentMessage:[NSString stringWithFormat:@"[%@]: %@", channel.userInfo, message] isStatus:NO];
160+
}
161+
}
162+
163+
- (void)ioFrameChannel:(PTChannel*)channel didEndWithError:(NSError*)error {
164+
if (connectedDeviceID_ && [connectedDeviceID_ isEqualToNumber:channel.userInfo]) {
165+
[self didDisconnectFromDevice:connectedDeviceID_];
166+
}
167+
168+
if (connectedChannel_ == channel) {
169+
[self presentMessage:[NSString stringWithFormat:@"Disconnected from %@", channel.userInfo] isStatus:YES];
170+
self.connectedChannel = nil;
171+
}
172+
}
173+
174+
175+
#pragma mark - Wired device connections
176+
177+
178+
- (void)startListeningForDevices {
179+
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
180+
181+
[nc addObserverForName:PTUSBDeviceDidAttachNotification object:PTUSBHub.sharedHub queue:nil usingBlock:^(NSNotification *note) {
182+
NSNumber *deviceID = [note.userInfo objectForKey:@"DeviceID"];
183+
//NSLog(@"PTUSBDeviceDidAttachNotification: %@", note.userInfo);
184+
NSLog(@"PTUSBDeviceDidAttachNotification: %@", deviceID);
185+
186+
dispatch_async(notConnectedQueue_, ^{
187+
if (!connectingToDeviceID_ || ![deviceID isEqualToNumber:connectingToDeviceID_]) {
188+
[self disconnectFromCurrentChannel];
189+
connectingToDeviceID_ = deviceID;
190+
connectedDeviceProperties_ = [note.userInfo objectForKey:@"Properties"];
191+
[self enqueueConnectToUSBDevice];
192+
}
193+
});
194+
}];
195+
196+
[nc addObserverForName:PTUSBDeviceDidDetachNotification object:PTUSBHub.sharedHub queue:nil usingBlock:^(NSNotification *note) {
197+
NSNumber *deviceID = [note.userInfo objectForKey:@"DeviceID"];
198+
//NSLog(@"PTUSBDeviceDidDetachNotification: %@", note.userInfo);
199+
NSLog(@"PTUSBDeviceDidDetachNotification: %@", deviceID);
200+
201+
if ([connectingToDeviceID_ isEqualToNumber:deviceID]) {
202+
connectedDeviceProperties_ = nil;
203+
connectingToDeviceID_ = nil;
204+
if (connectedChannel_) {
205+
[connectedChannel_ close];
206+
}
207+
}
208+
}];
209+
}
210+
211+
212+
- (void)didDisconnectFromDevice:(NSNumber*)deviceID {
213+
NSLog(@"Disconnected from device");
214+
if ([connectedDeviceID_ isEqualToNumber:deviceID]) {
215+
[self willChangeValueForKey:@"connectedDeviceID"];
216+
connectedDeviceID_ = nil;
217+
[self didChangeValueForKey:@"connectedDeviceID"];
218+
}
219+
}
220+
221+
222+
- (void)disconnectFromCurrentChannel {
223+
if (connectedDeviceID_ && connectedChannel_) {
224+
[connectedChannel_ close];
225+
self.connectedChannel = nil;
226+
}
227+
}
228+
229+
230+
- (void)enqueueConnectToLocalIPv4Port {
231+
dispatch_async(notConnectedQueue_, ^{
232+
dispatch_async(dispatch_get_main_queue(), ^{
233+
[self connectToLocalIPv4Port];
234+
});
235+
});
236+
}
237+
238+
239+
- (void)connectToLocalIPv4Port {
240+
PTChannel *channel = [PTChannel channelWithDelegate:self];
241+
channel.userInfo = [NSString stringWithFormat:@"127.0.0.1:%d", PTExampleProtocolIPv4PortNumber];
242+
[channel connectToPort:PTExampleProtocolIPv4PortNumber IPv4Address:INADDR_LOOPBACK callback:^(NSError *error, PTAddress *address) {
243+
if (error) {
244+
if (error.domain == NSPOSIXErrorDomain && (error.code == ECONNREFUSED || error.code == ETIMEDOUT)) {
245+
// this is an expected state
246+
} else {
247+
NSLog(@"Failed to connect to 127.0.0.1:%d: %@", PTExampleProtocolIPv4PortNumber, error);
248+
}
249+
} else {
250+
[self disconnectFromCurrentChannel];
251+
self.connectedChannel = channel;
252+
channel.userInfo = address;
253+
NSLog(@"Connected to %@", address);
254+
}
255+
[self performSelector:@selector(enqueueConnectToLocalIPv4Port) withObject:nil afterDelay:PTAppReconnectDelay];
256+
}];
257+
}
258+
259+
260+
- (void)enqueueConnectToUSBDevice {
261+
dispatch_async(notConnectedQueue_, ^{
262+
dispatch_async(dispatch_get_main_queue(), ^{
263+
[self connectToUSBDevice];
264+
});
265+
});
266+
}
267+
268+
269+
- (void)connectToUSBDevice {
270+
PTChannel *channel = [PTChannel channelWithDelegate:self];
271+
channel.userInfo = connectingToDeviceID_;
272+
channel.delegate = self;
273+
274+
[channel connectToPort:PTExampleProtocolIPv4PortNumber overUSBHub:PTUSBHub.sharedHub deviceID:connectingToDeviceID_ callback:^(NSError *error) {
275+
if (error) {
276+
if (error.domain == PTUSBHubErrorDomain && error.code == PTUSBHubErrorConnectionRefused) {
277+
NSLog(@"Failed to connect to device #%@: %@", channel.userInfo, error);
278+
} else {
279+
NSLog(@"Failed to connect to device #%@: %@", channel.userInfo, error);
280+
}
281+
if (channel.userInfo == connectingToDeviceID_) {
282+
[self performSelector:@selector(enqueueConnectToUSBDevice) withObject:nil afterDelay:PTAppReconnectDelay];
283+
}
284+
} else {
285+
connectedDeviceID_ = connectingToDeviceID_;
286+
self.connectedChannel = channel;
287+
//NSLog(@"Connected to device #%@\n%@", connectingToDeviceID_, connectedDeviceProperties_);
288+
//infoTextField_.stringValue = [NSString stringWithFormat:@"Connected to device #%@\n%@", deviceID, connectedDeviceProperties_];
289+
}
290+
}];
291+
}
292+
293+
@end

Peertalk Example/PTExampleProtocol.h

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#ifndef peertalk_PTExampleProtocol_h
2+
#define peertalk_PTExampleProtocol_h
3+
4+
#import <Foundation/Foundation.h>
5+
#include <stdint.h>
6+
7+
static const int PTExampleProtocolIPv4PortNumber = 2345;
8+
9+
enum {
10+
PTExampleFrameTypeDeviceInfo = 100,
11+
PTExampleFrameTypeTextMessage = 101,
12+
};
13+
14+
typedef struct _PTExampleTextFrame {
15+
const uint8_t *utf8text;
16+
} PTExampleTextFrame;
17+
18+
19+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>CFBundleDevelopmentRegion</key>
6+
<string>en</string>
7+
<key>CFBundleExecutable</key>
8+
<string>${EXECUTABLE_NAME}</string>
9+
<key>CFBundleIconFile</key>
10+
<string>Icon</string>
11+
<key>CFBundleIdentifier</key>
12+
<string>me.rsms.peertalk.${PRODUCT_NAME:rfc1034identifier}</string>
13+
<key>CFBundleInfoDictionaryVersion</key>
14+
<string>6.0</string>
15+
<key>CFBundleName</key>
16+
<string>${PRODUCT_NAME}</string>
17+
<key>CFBundlePackageType</key>
18+
<string>APPL</string>
19+
<key>CFBundleShortVersionString</key>
20+
<string>1.0</string>
21+
<key>CFBundleSignature</key>
22+
<string>????</string>
23+
<key>CFBundleVersion</key>
24+
<string>1</string>
25+
<key>LSMinimumSystemVersion</key>
26+
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
27+
<key>NSHumanReadableCopyright</key>
28+
<string>Copyright © 2012 __MyCompanyName__. All rights reserved.</string>
29+
<key>NSMainNibFile</key>
30+
<string>MainMenu</string>
31+
<key>NSPrincipalClass</key>
32+
<string>NSApplication</string>
33+
</dict>
34+
</plist>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//
2+
// Prefix header for all source files of the 'Peertalk Example' target in the 'Peertalk Example' project
3+
//
4+
5+
#ifdef __OBJC__
6+
#import <Cocoa/Cocoa.h>
7+
#endif

0 commit comments

Comments
 (0)