Permalink
Browse files

Initial commit

  • Loading branch information...
kylehickinson committed Nov 3, 2012
0 parents commit d1ef7196e482b225633355cd6e4e7c92cfbda472
Showing with 6,693 additions and 0 deletions.
  1. +4 −0 .gitignore
  2. +388 −0 Mac/Reflect.xcodeproj/project.pbxproj
  3. +19 −0 Mac/Reflect/RFAppDelegate.h
  4. +57 −0 Mac/Reflect/RFAppDelegate.m
  5. +36 −0 Mac/Reflect/RFConnectedService.h
  6. +39 −0 Mac/Reflect/RFConnectedService.m
  7. +103 −0 Mac/Reflect/RFFileMonitor.h
  8. +131 −0 Mac/Reflect/RFFileMonitor.m
  9. +110 −0 Mac/Reflect/RFPacketHeaders.h
  10. +48 −0 Mac/Reflect/RFReflect.h
  11. +312 −0 Mac/Reflect/RFReflect.m
  12. +134 −0 Mac/Reflect/RFServer.h
  13. +408 −0 Mac/Reflect/RFServer.m
  14. +38 −0 Mac/Reflect/Reflect-Info.plist
  15. +7 −0 Mac/Reflect/Reflect-Prefix.pch
  16. +14 −0 Mac/Reflect/Reflect.entitlements
  17. +5 −0 Mac/Reflect/en.lproj/Credits.rtf
  18. +2 −0 Mac/Reflect/en.lproj/InfoPlist.strings
  19. +3,287 −0 Mac/Reflect/en.lproj/MainMenu.xib
  20. +14 −0 Mac/Reflect/main.m
  21. BIN Mac/temp-icon-highlighted.png
  22. BIN Mac/temp-icon-highlighted@2x.png
  23. BIN Mac/temp-icon.png
  24. BIN Mac/temp-icon@2x.png
  25. +108 −0 README.md
  26. +10 −0 Reflect.xcworkspace/contents.xcworkspacedata
  27. +8 −0 Reflect.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
  28. +336 −0 iOS/Reflect Client.xcodeproj/project.pbxproj
  29. +18 −0 iOS/Reflect/AppDelegate.h
  30. +52 −0 iOS/Reflect/AppDelegate.m
  31. BIN iOS/Reflect/Default-568h@2x.png
  32. BIN iOS/Reflect/Default.png
  33. BIN iOS/Reflect/Default@2x.png
  34. +72 −0 iOS/Reflect/RFClient.h
  35. +325 −0 iOS/Reflect/RFClient.m
  36. +28 −0 iOS/Reflect/RFImageViewController.h
  37. +160 −0 iOS/Reflect/RFImageViewController.m
  38. +38 −0 iOS/Reflect/RFPulseActivityViewIndicator.h
  39. +96 −0 iOS/Reflect/RFPulseActivityViewIndicator.m
  40. +17 −0 iOS/Reflect/RFRootViewController.h
  41. +190 −0 iOS/Reflect/RFRootViewController.m
  42. +45 −0 iOS/Reflect/Reflect Client-Info.plist
  43. +14 −0 iOS/Reflect/Reflect Client-Prefix.pch
  44. +2 −0 iOS/Reflect/en.lproj/InfoPlist.strings
  45. +18 −0 iOS/Reflect/main.m
@@ -0,0 +1,4 @@
+xcuserdata
+.DS_Store
+build
+DerivedData

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -0,0 +1,19 @@
+//
+// RFAppDelegate.h
+// Reflect
+//
+// Created by Kyle Hickinson on 2012-10-15.
+// Copyright (c) 2012 Kyle Hickinson. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+#import "RFReflect.h"
+
+@interface RFAppDelegate : NSObject <NSApplicationDelegate>
+
+@property (nonatomic, strong) RFReflect *reflect;
+@property (strong) IBOutlet NSWindow *preferencesWindow;
+
+- (IBAction)randomizePasscodeNow:(id)sender;
+
+@end
@@ -0,0 +1,57 @@
+//
+// RFAppDelegate.m
+// Reflect
+//
+// Created by Kyle Hickinson on 2012-10-15.
+// Copyright (c) 2012 Kyle Hickinson. All rights reserved.
+//
+
+#import "RFAppDelegate.h"
+#import <SystemConfiguration/SystemConfiguration.h>
+
+@implementation RFAppDelegate
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
+{
+ NSString *computerName = (__bridge NSString *)SCDynamicStoreCopyComputerName(NULL, NULL);
+ if (computerName == nil) {
+ computerName = @"";
+ }
+
+ NSUserDefaults *defaults = [[NSUserDefaultsController sharedUserDefaultsController] defaults];
+
+ // I should probably throw all these keys in a header file so I can stop trying to remember all of them...
+ [defaults registerDefaults:@{
+ @"server-start-on-launch" : @YES,
+ @"passcode-enabled" : @NO,
+ @"passcode" : @"",
+ @"passcode-randomize" : @YES,
+ @"passcode-simple" : @YES,
+ @"bonjour-use-name" : @NO,
+ @"bonjour-name" : computerName,
+ @"bonjour-use-type" : @NO,
+ @"bonjour-type" : @"_reflect",
+ @"recent-files" : @[ ]
+ }];
+
+ // (Maybe) Start Reflect server.
+ self.reflect = [[RFReflect alloc] init];
+}
+
+- (void)randomizePasscodeNow:(id)sender
+{
+ [self.reflect randomizePasscode];
+}
+
+- (void)_showPreferences:(id)sender
+{
+ [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
+ [self.preferencesWindow makeKeyAndOrderFront:nil];
+}
+
+- (void)_quit
+{
+ [[NSApplication sharedApplication] terminate:self];
+}
+
+@end
@@ -0,0 +1,36 @@
+//
+// RFConnectedService.h
+// Reflect
+//
+// Created by Kyle Hickinson on 2012-10-20.
+// Copyright (c) 2012 Kyle Hickinson. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+/**
+ The RFConnectedService class represents a service connected to the server.
+
+ This would be written usually as a struct, but we can't have objects in a struct
+ and I don't feel like bridging between CF and NS objects every time.
+ */
+@interface RFConnectedService : NSObject
+
+/** Whether or not the service has entered a passcode—if they need too—and is ready to receive data. */
+@property (nonatomic, assign) BOOL enteredPasscode;
+
+/** The file descriptor for the socket that is opened. */
+@property (nonatomic, assign) CGFloat socketDescriptor;
+
+/** The input stream for this service. */
+@property (nonatomic, strong) NSInputStream *inputStream;
+
+/** The output stream for this service. */
+@property (nonatomic, strong) NSOutputStream *outputStream;
+
+/**
+ Disconnect this client by closing its streams and closing the socket.
+ */
+- (void)disconnect;
+
+@end
@@ -0,0 +1,39 @@
+//
+// RFConnectedService.m
+// Reflect
+//
+// Created by Kyle Hickinson on 2012-10-20.
+// Copyright (c) 2012 Kyle Hickinson. All rights reserved.
+//
+
+#import "RFConnectedService.h"
+
+@implementation RFConnectedService
+
+- (BOOL)isEqual:(id)object
+{
+ if ([object isKindOfClass:[RFConnectedService class]]) {
+ return ((RFConnectedService *)object).socketDescriptor == self.socketDescriptor;
+ }
+ return NO;
+}
+
+- (id)init
+{
+ if ((self = [super init])) {
+ self.enteredPasscode = NO;
+ self.socketDescriptor = 0;
+ }
+ return self;
+}
+
+- (void)disconnect
+{
+ [self.inputStream close];
+ [self.outputStream close];
+ [self.inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
+ [self.outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
+ close(self.socketDescriptor);
+}
+
+@end
@@ -0,0 +1,103 @@
+//
+// RFFileMonitor.h
+// Reflect
+//
+// Created by Kyle Hickinson on 2012-10-21.
+// Copyright (c) 2012 Kyle Hickinson. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+extern NSString * const RFFileMonitorErrorDomain;
+
+/**
+ An enumeration of errors that could appear in the fileMonitor:failedToBeginMonitoringWithError
+ */
+typedef enum : NSInteger {
+ /**
+ The file failed to open properly.
+ */
+ RFFileMonitorFailedOpenError = -200L,
+
+ /**
+ The path given was a directory, which is currently unsupported by RFFileMonitor
+ */
+ RFFileMonitorFileIsDirectoryError = -201L,
+
+ /**
+ The given path did not exist.
+ */
+ RFFileMonitorFileDoesntExistError = -202L,
+
+ /**
+ The call to kqueue() faliled.
+ */
+ RFFileMonitorQueueFailedError = -203L,
+
+} RFFileMonitorErrorCode;
+
+@class RFFileMonitor;
+
+/**
+ The file monitor delegate communicates when a path changed or when erorrs occur.
+ */
+@protocol RFFileMonitorDelegate<NSObject>
+@required
+
+/**
+ A file under watch changed.
+
+ @param fileMonitor The sender
+ @param path The path of the file changed.
+ */
+- (void)fileMonitor:(RFFileMonitor *)fileMonitor pathDidChange:(NSString *)path;
+
+@optional
+
+/**
+ An error occured while attempting to begin monitoring a file.
+
+ @param fileMonitor The sender
+ @param error The error that occured with the domain RFFileMonitorErrorDomain with possible codes in
+ the RFFileMonitorErrorCode enumeration.
+ */
+- (void)fileMonitor:(RFFileMonitor *)fileMonitor failedToBeginMonitoringWithError:(NSError *)error;
+
+/**
+ The file monitor successfully began monitoring the file at path.
+
+ @param fileMonitor The sender
+ @param path The path to the file that is being monitored.
+ */
+- (void)fileMonitor:(RFFileMonitor *)fileMonitor didBeginMonitoringPath:(NSString *)path;
+
+@end
+
+/**
+ The RFFileMonitor class allows the developer to watch a specific file for given changes.
+ At the moment RFFileMonitor only allows watching 1 file at a time, but can be easily
+ modified to watch multiple files if needed, or even directories using FSEvent APIs.
+ */
+@interface RFFileMonitor : NSObject {
+ struct {
+ unsigned respondsToFailedBegin:1;
+ unsigned respondsToDidBeginMonitoring:1;
+ } _flags;
+}
+
+/** The delegate */
+@property (nonatomic, weak) id<RFFileMonitorDelegate> delegate;
+
+/**
+ Begin monitoring a file with a given path.
+
+ @param path The path to the file to monitor.
+ */
+- (void)beginMonitoringForPath:(NSString *)path;
+
+/**
+ Stop monitoring the file that was originally watched after calling beginMonitoringForPath:
+ */
+- (void)stopMonitoring;
+
+@end
@@ -0,0 +1,131 @@
+//
+// RFFileMonitor.m
+// Reflect
+//
+// Created by Kyle Hickinson on 2012-10-21.
+// Copyright (c) 2012 Kyle Hickinson. All rights reserved.
+//
+
+#import "RFFileMonitor.h"
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <fcntl.h>
+
+NSString * const RFFileMonitorErrorDomain = @"RFFileMonitorErrorDomain";
+
+@interface RFFileMonitor ()
+
+@property (nonatomic, copy) NSString *path;
+@property (nonatomic, assign) int fileDescriptor;
+@property (nonatomic, assign) int queue;
+@property (nonatomic, strong) NSThread *monitoringThread;
+
+@end
+
+@implementation RFFileMonitor
+
+- (void)beginMonitoringForPath:(NSString *)path
+{
+ if (self.queue > 0) {
+ // Currently already watching a file...
+ // I'm going to go ahead and just close it, maybe offer user a choice or just fail?
+ [self stopMonitoring];
+ }
+
+ BOOL isDirectory = NO;
+ if (![[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory]) {
+ if (_flags.respondsToFailedBegin) {
+ [self.delegate fileMonitor:self failedToBeginMonitoringWithError:[NSError errorWithDomain:RFFileMonitorErrorDomain code:RFFileMonitorFileDoesntExistError userInfo:nil]];
+ }
+ }
+
+ // File exists, but if its a directory we're opting out. Though we could watch a directory using the FSEventStream's.
+ if (isDirectory) {
+ if (_flags.respondsToFailedBegin) {
+ [self.delegate fileMonitor:self failedToBeginMonitoringWithError:[NSError errorWithDomain:RFFileMonitorErrorDomain code:RFFileMonitorFileIsDirectoryError userInfo:nil]];
+ }
+ return;
+ }
+
+ // Get the file descriptor.
+ self.fileDescriptor = open([path UTF8String], O_EVTONLY);
+
+ if (self.fileDescriptor < 0) {
+ if (_flags.respondsToFailedBegin) {
+ [self.delegate fileMonitor:self failedToBeginMonitoringWithError:[NSError errorWithDomain:RFFileMonitorErrorDomain code:RFFileMonitorFailedOpenError userInfo:nil]];
+ }
+ return;
+ };
+
+ // Now setup kqueue.
+ self.path = path;
+ self.queue = kqueue();
+ if (self.queue < 0) {
+ if (_flags.respondsToFailedBegin) {
+ [self.delegate fileMonitor:self failedToBeginMonitoringWithError:[NSError errorWithDomain:RFFileMonitorErrorDomain code:RFFileMonitorQueueFailedError userInfo:nil]];
+ }
+ close(self.fileDescriptor);
+ return;
+ }
+
+ // Start the monitoring thread, and we're off!
+ self.monitoringThread = [[NSThread alloc] initWithTarget:self selector:@selector(_monitorInBackground) object:nil];
+ [self.monitoringThread start];
+
+ if (_flags.respondsToDidBeginMonitoring) {
+ [self.delegate fileMonitor:self didBeginMonitoringPath:self.path];
+ }
+}
+
+- (void)stopMonitoring
+{
+ close(self.fileDescriptor);
+ close(self.queue);
+ [self.monitoringThread cancel];
+}
+
+- (void)setDelegate:(id<RFFileMonitorDelegate>)delegate
+{
+ _delegate = delegate;
+ memset(&_flags, 0, sizeof(_flags));
+
+ if (_delegate) {
+ _flags.respondsToDidBeginMonitoring = [_delegate respondsToSelector:@selector(fileMonitor:didBeginMonitoringPath:)];
+ _flags.respondsToFailedBegin = [_delegate respondsToSelector:@selector(fileMonitor:failedToBeginMonitoringWithError:)];
+ }
+}
+
+#pragma mark - Private
+
+- (void)_monitorInBackground
+{
+ struct kevent change;
+ struct kevent event;
+ struct timespec timeout;
+
+ // Setup kevent changes
+ EV_SET(&change, self.fileDescriptor, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, NOTE_DELETE | NOTE_WRITE, 0, 0);
+
+ // Setup timeout
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 500000000;
+
+ // Register for events
+ for (;;)
+ {
+ // Make sure we check if the thread was cancelled during each loop run.
+ if ([[NSThread currentThread] isCancelled]) {
+ [NSThread exit];
+ }
+
+ if (kevent(self.queue, &change, 1, &event, 1, &timeout) != -1) {
+ if (event.fflags & NOTE_WRITE || event.fflags & NOTE_DELETE) {
+ [self.delegate fileMonitor:self pathDidChange:self.path];
+ }
+ }
+ }
+}
+
+@end
Oops, something went wrong.

0 comments on commit d1ef719

Please sign in to comment.