Getting libomv to connect using IronScheme?

Oct 15, 2014 at 4:33 AM
Edited Oct 15, 2014 at 4:34 AM
Hey, I apologize if this is too simple of a question, I decided to go through SICP and use IronScheme to start me on my road to lisp, because I wanted to play around with the .Net library libomv.

Currently I'm trying to get myself up and running by connecting, translating the following code into ironscheme:

http://lib.openmetaverse.org/wiki/IronPython/Simple_Login

Problem is once I get to login, I'm stuck. I can't get IronScheme to accept, the code I have so far is:


(import
(rnrs)
(ironscheme clr))

(clr-using System.Reflection)

(clr-static-call Assembly LoadFile "g:\Workspace\lisp_bot\IronScheme\libomv\OpenMetaverse.dll")
(clr-using OpenMetaverse)

(define client (clr-new OpenMetaverse.GridClient))
(clr-call #f OpenMetaverse.GridClient.Network.Login client "FirstName" "LastName" "Password" "Ironbot" "IronBot1")


The login attempt gets me this error:
(clr-call #f OpenMetaverse.GridClient.Network.Login client "FirstName" "LastName" "Password" "Ironbot" "IronBot1")
Unhandled exception during evaluation:
&who: "clr-call"
&message: "member could not be resolved on type: Object"
&syntax:
form: ('#f 'OpenMetaverse.GridClient.Network.Login g$client$426$S8JTA '"FirstName" '"LastName" '"Password" '"Ironbot" '"IronBot1")
subform: "OpenMetaverse.GridClient.Network.Login"

Any help would be greatly appreciated!

-- Raz

P.s. - Once I have the assembly loaded, is there something like Python's dir() command so I can inspect available library functions and members via the repl?
Coordinator
Oct 15, 2014 at 5:16 AM
Edited Oct 15, 2014 at 5:16 AM
Here is a quick example (says login failed for me so I dont know if it is actually working):
(import 
  (ironscheme) 
  (ironscheme clr)
  (ironscheme clr shorthand))

(clr-reference OpenMetaverse)
(clr-using OpenMetaverse)

(let-clr-type [(client (GridClient))]
  (if (client -> Network : Login ("Test" "User" "password" "IronBot" "IronBot 0.1"))
      (displayln "Logged in")
      (displayln "Login failed")))
You will need to look at the shorthand library's source to understand the shorthand like -> and : .

There is nothing that will reflect over a standard .NET assembly out of the box. Just use Reflector, it is easier :)
Oct 15, 2014 at 6:34 AM
Edited Oct 15, 2014 at 8:28 AM
It works! Thank you so much! I'll go check out that shorthand library xD

Ooh ok, I'll check out Reflector then :)
Coordinator
Oct 15, 2014 at 7:50 AM
Hey, quick question, is there a way to explore the api from the repl? So I can type things in and try them out and play around with them? Like python's dir() command?
There is nothing that will reflect over a standard .NET assembly out of the box. Just use Reflector (or favourite decompiler), it is easier :)
Oct 15, 2014 at 9:38 AM
Ahh, apologies! I read over that too quickly!

I found your blog post on http://xacc.wordpress.com/2009/08/21/ironscheme-clr-shorthand/ so I'm trying to apply it to event handlers now :)
Does (let-clr-type [(client (GridClient))] (clr-event-add! GridClient (client : Self . IM) client on-im)) seem like the right track?
Coordinator
Oct 15, 2014 at 9:46 AM
There is no support for events with shorthand, but you pretty close.

The following should work:
(clr-event-add! AgentManager IM  (client -> Self) on-im)
But the event type is EventHandler<InstantMessageEventArgs> which may not be convertible from scheme procedure.

Also note: In shorthand -> is used for fields. You will note Self is a field in GridClient.
Oct 15, 2014 at 10:39 AM
It didn't complain when I entered it! So I'll google and figure out handlers, thanks so much!
Oct 15, 2014 at 4:30 PM
Edited Oct 15, 2014 at 4:39 PM
Ok so handlers are working! I'll post the code piecemealed together using leppie's code snippets above:
(import 
  (ironscheme) 
  (ironscheme clr)
  (ironscheme clr shorthand))

(clr-reference OpenMetaverse)
(clr-using OpenMetaverse)

(define (on-im s e) (displayln "Got an IM!"))

(define (login)
    (let-clr-type [(client (GridClient))]
        (if (client -> Network : Login ("FirstName" "LastName" "password" "IronBot" "IronBot 0.1"))
            (begin
                (displayln "Logged in")
                (clr-event-add! AgentManager IM  (client -> Self) on-im))
            (displayln "Login failed"))))
    
(define (logout) (let-clr-type [(client (GridClient))] (client -> Network : Logout ())))
Leppie was kind enough to give some answers to questions I had in the chatroom, I'll repost some of the information here for other people who may come by:

15:51 < leppie> on an already existing object, you can use (with-clr-type [(client GridClient)] body ...)
15:52 < RazWelle1> Ooh ok, what about when creating one to use throughout the rest of the program? I only need to create one client object but I have to use it everywhere
15:55 < leppie> yeah, you would have to type that alot :) Not sure if there is a way to type a value in the top level


6:07 < RazWelle1> Can I just assign the object via define and use it?
16:07 < leppie> that might be a small fix, I think I implemented a lot of typed stuff after
16:07 < leppie> define-clr-type is a define lambda only
16:07 < RazWelle1> Sorry this is my very first brush with lisp beyond skimming books so most of my knowledge is C and Python
16:08 < RazWelle1> ohh I see
16:08 < leppie> so you cant define values/variables for it
16:08 < RazWelle1> So that's why I was having trouble using the objects I instantiated with define xD
16:08 < leppie> I understand ;p
16:09 < leppie> let me think about a solution that does not involve a macro
16:09 < RazWelle1> thank you for being so helpful wow

So basically now I"m just trying to figure out how to instantiate .Net objects and keep them around to reuse in various functions, or if there's a more Scheme-like way of doing it that I"m not aware of, I'd be grateful for any sage advice anyone could give me :)
Oct 17, 2014 at 2:20 PM
Edited Oct 17, 2014 at 2:32 PM
So with much help from Leppie, here's the assembled code. The latest IronScheme source repo contains a new function he put in, "define-clr-type" to allow for a global object to be made, which I needed to reuse the client object across functions.

The code includes login, and callbacks!
(import 
  (ironscheme) 
  (ironscheme clr)
  (ironscheme clr shorthand))

(clr-reference OpenMetaverse)
(clr-using OpenMetaverse)

(define im "")
(define-clr-type client GridClient (clr-new GridClient))

(define-clr-type (on-im (s Object) (e InstantMessageEventArgs))
    (begin
        (displayln "Got IM.")
        (displayln (e : IM -> Message))))

(define (login)
        (if (client -> Network : Login ("FirstName" "LastName" "pass" "IronBot" "IronBot 0.1"))
            (begin
                (displayln "Logged in")
                (clr-event-add! AgentManager IM  (client -> Self) on-im))
            (displayln "Login failed")))
    
(define (logout) (client -> Network : Logout ()))