Esempio n. 1
0
// Schedules the Stream on a new thread
// and starts delivering events on the channel.
//
// https://developer.apple.com/library/mac/documentation/Darwin/Reference/FSEvents_Ref/Reference/reference.html#jumpTo_20
// https://developer.apple.com/library/mac/documentation/Darwin/Reference/FSEvents_Ref/Reference/reference.html#jumpTo_17
func (s *Stream) Start() bool {
	type watchSuccessData struct {
		runloop C.CFRunLoopRef
		stream  Stream
	}

	successChan := make(chan C.CFRunLoopRef)

	go func() {
		C.FSEventStreamScheduleWithRunLoop(s.cstream,
			C.CFRunLoopGetCurrent(), C.kCFRunLoopCommonModes)
		ok := C.FSEventStreamStart(s.cstream) != C.FALSE
		if ok {
			successChan <- C.CFRunLoopGetCurrent()
			C.CFRunLoopRun()
		} else {
			successChan <- nil
		}
	}()

	runloop := <-successChan

	if runloop == nil {
		return false
	}
	s.runloop = runloop
	return true
}
Esempio n. 2
0
func startScanner(dir string) {
	lock.Lock()
	chans[dir] = make(chan string)
	lock.Unlock()

	cpaths := C.fswatch_make_mutable_array()
	defer C.free(unsafe.Pointer(cpaths))

	path := C.CString(dir)
	str := C.CFStringCreateWithCString(nil, path, C.kCFStringEncodingUTF8)
	defer C.free(unsafe.Pointer(path))
	defer C.free(unsafe.Pointer(str))

	C.CFArrayAppendValue(cpaths, unsafe.Pointer(str))

	ctx := C.FSEventStreamContext{info: unsafe.Pointer(C.CString(dir))}

	stream := C.fswatch_create(&ctx, cpaths, now, C.CFTimeInterval(interval/time.Second), cflags)

	go func() {
		C.FSEventStreamScheduleWithRunLoop(stream, C.CFRunLoopGetCurrent(), C.kCFRunLoopCommonModes)
		C.FSEventStreamStart(stream)
		C.CFRunLoopRun()
	}()
}
Esempio n. 3
0
func (w *Watcher) watchPath(path string, options *Options) error {
	path, _ = filepath.Abs(path)

	w.wmut.Lock()
	_, found := w.watches[path]
	w.wmut.Unlock()

	if !found {
		cPaths := C.ArrayCreateMutable(C.int(1))
		defer C.CFRelease(C.CFTypeRef(cPaths))

		cpath := C.CString(path)
		defer C.free(unsafe.Pointer(cpath))

		str := C.CFStringCreateWithCString(nil, cpath, C.kCFStringEncodingUTF8)
		C.CFArrayAppendValue(cPaths, unsafe.Pointer(str))

		context := C.FSEventStreamContext{info: unsafe.Pointer(&w.internalEvent)}
		latency := C.CFTimeInterval(0)
		if options != nil && options.Throttle {
			latency = C.CFTimeInterval(options.ThrottleDuration / time.Second)
		}
		stream := C.EventStreamCreate(&context, cPaths, C.kFSEventStreamEventIdSinceNow+(1<<64), latency)
		w.wmut.Lock()
		w.watches[path] = stream
		w.wmut.Unlock()
		C.FSEventStreamScheduleWithRunLoop(stream, w.rlref, C.kCFRunLoopDefaultMode)
		C.FSEventStreamStart(stream)
	}

	return nil
}
Esempio n. 4
0
// Start listening to an event stream.
func (es *EventStream) Start() {
	cPaths := C.ArrayCreateMutable(C.int(len(es.Paths)))
	defer C.CFRelease(C.CFTypeRef(cPaths))

	for _, p := range es.Paths {
		p, _ = filepath.Abs(p)
		cpath := C.CString(p)
		defer C.free(unsafe.Pointer(cpath))

		str := C.CFStringCreateWithCString(nil, cpath, C.kCFStringEncodingUTF8)
		C.CFArrayAppendValue(cPaths, unsafe.Pointer(str))
	}

	since := C.FSEventStreamEventId(EventIDSinceNow)
	if es.Resume {
		since = C.FSEventStreamEventId(es.EventID)
	}

	if es.Events == nil {
		es.Events = make(chan []Event)
	}

	es.registryID = registry.Add(es)
	context := C.FSEventStreamContext{}
	info := C.uintptr_t(es.registryID)
	latency := C.CFTimeInterval(float64(es.Latency) / float64(time.Second))
	if es.Device != 0 {
		es.stream = C.EventStreamCreateRelativeToDevice(&context, info, C.dev_t(es.Device), cPaths, since, latency, C.FSEventStreamCreateFlags(es.Flags))
	} else {
		es.stream = C.EventStreamCreate(&context, info, cPaths, since, latency, C.FSEventStreamCreateFlags(es.Flags))
	}

	started := make(chan struct{})

	go func() {
		runtime.LockOSThread()
		es.rlref = C.CFRunLoopGetCurrent()
		C.FSEventStreamScheduleWithRunLoop(es.stream, es.rlref, C.kCFRunLoopDefaultMode)
		C.FSEventStreamStart(es.stream)
		close(started)
		C.CFRunLoopRun()
	}()

	if !es.hasFinalizer {
		runtime.SetFinalizer(es, finalizer)
		es.hasFinalizer = true
	}

	<-started
}
Esempio n. 5
0
// Start creates a FSEventStream for the given path and schedules it with
// global runloop. It's a nop if the stream was already started.
func (s *stream) Start() error {
	if s.ref != nilstream {
		return nil
	}
	wg.Wait()
	p := C.CFStringCreateWithCStringNoCopy(nil, C.CString(s.path), C.kCFStringEncodingUTF8, nil)
	path := C.CFArrayCreate(nil, (*unsafe.Pointer)(unsafe.Pointer(&p)), 1, nil)
	ref := C.FSEventStreamCreate(nil, (C.FSEventStreamCallback)(C.gostream),
		&s.ctx, path, C.FSEventStreamEventId(atomic.LoadUint64(&since)), latency, flags)
	if ref == nilstream {
		return errCreate
	}
	C.FSEventStreamScheduleWithRunLoop(ref, runloop, C.kCFRunLoopDefaultMode)
	if C.FSEventStreamStart(ref) == C.Boolean(0) {
		C.FSEventStreamInvalidate(ref)
		return errStart
	}
	C.CFRunLoopWakeUp(runloop)
	s.ref = ref
	return nil
}