mfikes / ambly

ClojureScript REPL into embedded JavaScriptCore
http://ambly.fikesfarm.com
Eclipse Public License 1.0
541 stars 21 forks source link

Apple TV Support (initial legwork) #109

Closed sherbondy closed 8 years ago

sherbondy commented 8 years ago

Hey Mike et. al.

Supporting tvOS pretty much just works out of the box. Had to make a couple tweaks to the podspec, and waiting upstream for GCDWebServer 3.3 release. Once that happens, all you need to do is add:

s.tvos.deployment_target = '9.0'

to Ambly.podspec.

Also want to note that tvOS unfortunately does not support writing to the app library directory, so for the privateDocumentsDirectory method in the sample app I'd recommend doing an #ifdef (or just using caches for both targets if we don't care about persisting the cljs output between app launches):

- (NSURL *)privateDocumentsDirectory
{
    NSSearchPathDirectory directory;
    #ifdef TARGET_OS_TV
        directory = NSCachesDirectory;
    #else
        directory = NSLibraryDirectory;
    #endif
    NSURL *userDirectory = [[[NSFileManager defaultManager] URLsForDirectory:directory inDomains:NSUserDomainMask] lastObject];
    return [userDirectory URLByAppendingPathComponent:@"Private Documents"];
}

One last thing, the Podfile for any app which wants to target multiple OSes can just add an additional platform declaration, e.g.:

platform :ios, '9.0'
platform :tvos, '9.0'

Pretty sweet!

mfikes commented 8 years ago

@sherbondy Awesome! If you'd like to contribute this, get in the omcljs CA.

Are you doing this with actual hardware, or a simulator of some sort? (I haven't checked this tvOS dev scene out.)

It sounds like your suggested revisions are along similar lines to some of the stuff needed for Ambly OS X support (which is currently brewing in master).

sherbondy commented 8 years ago

Alright, email sent! Testing on both hardware and simulator. Need to be careful with AppleTV simulator because apparently the directory permissions are not correct on the simulator, but otherwise it is pretty straightforward to try things out. Just another mode of the regular ole' iOS simulator.

mfikes commented 8 years ago

Cool. The Private Documents directory is created and used on iOS per Apple's guidance.

I suppose all of this data is ephemeral anyway. Does the sample app itself actually run on tvOS? (Or would another sample app be added, for that platform?)

Interestingly, I ran into a slightly different issue on OS X with this directory ending up in ~/Library/Private Documents.

I suppose the cool thing is that none of this affects Ambly proper, given that it lets the client choose where to put the compiler output. But, you're right, it could affect the sample app.

sherbondy commented 8 years ago

Can reuse the same app source code by adding a different build target for tvos. Could also prepare a distinct sample app if special casing for each platform gets out of hand and distracts from the core idea of how to get up and running.

mfikes commented 8 years ago

@sherbondy if you get something to show up on your TV set that looks like it came from ClojureScript (like :cljs.user/foo or some such), take a picture of it and Tweet it. “One small step…”

sherbondy commented 8 years ago

Okay, I'll try for one better tomorrow night! Will attempt a little video with working code sample.

sherbondy commented 8 years ago

Whoops, one night late! Here we go: https://gist.github.com/sherbondy/f196dedb71e14b5d11d2 https://www.youtube.com/watch?v=eaWy5mliO38

Not sure why I'm running into the "Use of undeclared Var" issue. Otherwise pretty sweet!

mfikes commented 8 years ago

@sherbondy for the undeclared Var stuff it is likely because you connected to a running app and all that is needed is to make use of the :analyze-path REPL option to get it to initialize the REPL with the compiler analysis cache https://github.com/clojure/clojurescript/wiki/REPL-options#analyze-path

This blog post elaborates on the setting and, in particular, illustrates using it with Ambly: http://blog.fikesfarm.com/posts/2015-06-10-analyze-path-ftw.html

mfikes commented 8 years ago

Hey @sherbondy, in your video demo, your println call doesn't seem to emit a newline. Normally it looks like this:

To quit, type: :cljs/quit
cljs.user=> (println "hello world")
hello world
nil
cljs.user=> 

If there isn's some immediately obvious explanation that you know would cause this for this environment, perhaps log a ticket against Ambly—it shouldn't be doing that.

sherbondy commented 8 years ago

Hmm, some further experimenting this evening:

  1. :analyze-path resolved the undeclared Var issue.
  2. println consistently fails to emit a newline until I call (enable-console-print!). Then it works as expected.
  3. I am running into java.io.IOException: Unable to mount WebDAV at http://127.0.0.1:49153 somewhat frequently. Although doing a rm -rf /Volumes/Ambly-[ID] does seem to resolve temporarily. Would really like to understand what's causing the mounting issue. Something in Mac OS?

Quick console / REPL log:

nREPL server started on port 63716 on host 127.0.0.1 - nrepl://127.0.0.1:63716
REPL-y 0.3.7, nREPL 0.2.10
Clojure 1.7.0
Java HotSpot(TM) 64-Bit Server VM 1.8.0_51-b16
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

user=> (require '[cljs.repl :as repl])
nil
user=> (require '[ambly.core :as ambly])
nil
user=> (repl/repl (ambly/repl-env) :analyze-path "src")

[1] LetterComb on Apple TV (embp)

[R] Refresh

Choice: 1
java.io.IOException: Unable to mount WebDAV at http://127.0.0.1:49153
    at ambly.core$eval6044$fn__6045.invoke(core.clj:437)
    at clojure.lang.MultiFn.invoke(MultiFn.java:243)
    at ambly.core$setup.invoke(core.clj:521)
    at ambly.core.JscEnv._setup(core.clj:634)
    at cljs.repl$repl_STAR_$fn__5807.invoke(repl.cljc:827)
    at cljs.compiler$with_core_cljs.invoke(compiler.cljc:1149)
    at cljs.repl$repl_STAR_.invoke(repl.cljc:824)
    at cljs.repl$repl.doInvoke(repl.cljc:977)
    at clojure.lang.RestFn.invoke(RestFn.java:439)
    at user$eval6133.invoke(form-init259993913000397361.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6782)
    at clojure.lang.Compiler.eval(Compiler.java:6745)
    at clojure.core$eval.invoke(core.clj:3081)
    at clojure.main$repl$read_eval_print__7099$fn__7102.invoke(main.clj:240)
    at clojure.main$repl$read_eval_print__7099.invoke(main.clj:240)
    at clojure.main$repl$fn__7108.invoke(main.clj:258)
    at clojure.main$repl.doInvoke(main.clj:258)
    at clojure.lang.RestFn.invoke(RestFn.java:1523)
    at clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__623.invoke(interruptible_eval.clj:58)
    at clojure.lang.AFn.applyToHelper(AFn.java:152)
    at clojure.lang.AFn.applyTo(AFn.java:144)
    at clojure.core$apply.invoke(core.clj:630)
    at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1868)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at clojure.tools.nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:56)
    at clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn__665$fn__668.invoke(interruptible_eval.clj:191)
    at clojure.tools.nrepl.middleware.interruptible_eval$run_next$fn__660.invoke(interruptible_eval.clj:159)
    at clojure.lang.AFn.run(AFn.java:22)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Not connected.
To quit, type: :cljs/quit
cljs.user=> :cljs/quit
nil
user=> (repl/repl (ambly/repl-env) :analyze-path "src")

[1] LetterComb on Apple TV (embp)

[R] Refresh

Choice: R

[1] LetterComb on Apple TV (embp)

[R] Refresh

Choice: 1

Connecting to LetterComb on Apple TV (embp) ...

To quit, type: :cljs/quit
cljs.user=> (in-ns 'lettercomb.core)
nil
lettercomb.core=> (println "hello world")
hello worldnil
lettercomb.core=> (+ 1 1)
2
lettercomb.core=> (enable-console-print!)
nil
lettercomb.core=> (println "hello world")
nil
lettercomb.core=> board
#object [cljs.core.Atom {:val [[:H :E :L :L :O :blank :blank :blank :blank] [:blank :T :H :E :R :E :blank :blank :blank] [:blank :blank :blank :blank :blank :blank :blank :blank :blank] [:blank :blank :blank :blank :blank :blank :blank :blank :blank] [:blank :blank :blank :blank :blank :blank :blank :blank :blank] [:blank :blank :blank :blank :blank :blank :blank :blank :blank] [:blank :blank :blank :blank :blank :blank :blank :blank :blank] [:blank :blank :blank :blank :blank :blank :blank :blank :blank] [:blank :blank :blank :blank :blank :blank :blank :blank :blank] [:blank :blank :blank :blank :blank :blank :blank :blank :blank] [:blank :blank :blank :blank :blank :blank :blank :blank :blank]]}]
lettercomb.core=> (write-word! board [1 1] "BETTER")
nil
lettercomb.core=>     
sherbondy commented 8 years ago

Hmm, may be an issue with GCDWebServer as well. Seeing lots of odd logs from the Application:

[WARNING] Unknown DAV property requested "quota-available-bytes"
[WARNING] Unknown DAV property requested "quota-used-bytes"
[WARNING] Unknown DAV property requested "quota"
[WARNING] Unknown DAV property requested "quotaused"
[WARNING] Unknown DAV property requested "getetag"
[WARNING] Unknown DAV property requested "getetag"
[WARNING] Unknown DAV property requested "getetag"
[ERROR] Error while writing to socket 17: Broken pipe (32)
[WARNING] Unknown DAV property requested "getetag"
[WARNING] Unknown DAV property requested "getetag"
[WARNING] Unknown DAV property requested "getetag"
[ERROR] Error while writing to socket 17: Broken pipe (32)
[ERROR] Error while writing to socket 17: Protocol wrong type for socket (41)
mfikes commented 8 years ago

@sherbondy yeah, stale mount points can happen, but they should be rare. Maybe they've increased with the latest GCDWebServer. The warnings you are seeing are normal.

There is some info on this stuff in the Connectivity page in the Wiki.

mfikes commented 8 years ago

Closing this as this support is now in the branch, and will ultimately be merged in to master.