저는 준비 됐어

저는 준비 됐어

Share Comments

Tale of Two Fishes

Tale of Two Fishes

Share Comments

With a Twist

Weapon With a Twist

Share Comments

Tuff's Saloon

Tuff's Saloon

Share Comments

Big Man Japan

Big Man Japan

Share Comments

.NET JavaScript Integration with EdgeJS

Background

Often times, our sales team will approach a client and talk up our integration with blue-tooth peripherals, on device bar-code scanners, network printers, etc., usually displaying the capabilities of the latest brand-name mobile device. I have been in rooms when these sales discussions are taking place, and it is really a joy to see the excitement our potential customers have as the wheels start turning; each person thinking of how our integration with X will solve some Y set of problems their company is facing.

The product my company develops is designed to be cross-platform. Built on web technologies, we are able to support Android, iOS, PC, Mac, or nearly any other system that runs a proper web browser.

Although HTML and JavaScript get us pretty far, there is always going to be some area where it’s necessary to have a deeper interaction with the application’s host system. For iOS and Android we have been using Cordova (although having to jump through hoops with each release). For Windows hardware integrations, our options have been pretty poor.

A couple weeks go by, the sale is finalized, the contract ink is dry, and the project kicks off. Now our integration and development teams start to encounter hurdles.

“We don’t support Android”
“Our entire enterprise is required to use Internet Explorer”
“We already have a support contract with Dell”
“We plan to use Windows Mobile handhelds we purchased 5 years ago”
“Our users are allowed and encouraged to use their own mobile devices”

Luckily, these types of problems are where web technologies really shine. “OK, no problem. We ensure you that our application with all desired integrations work well on whatever platform you choose.” Making that promise a reality is where I find a lot of enjoyment in my job.

Why .NET

Out of all of our active projects, Windows is probably the least requested platform. However, we still do our best to make sure all of the features our sales team advertised on Android and iOS devices are available on Windows.

To make it happen, it’s really hard to avoid .NET

  • It’s much easier to develop with than C++; and, for the same reason, many hardware manufacturers offer .NET SDKs to integrate with their products.
  • Microsoft always includes a .NET runtime on default installations of Windows.
  • Getting help is easy.

Offline GPS (Hurdle #1)

The hurdle that spawned the creation of this article is related to GPS and location services on Windows. Modern browsers already include a location service, and they work pretty well. But, the location API built into desktop browsers turned out to be very poor for a few of our customers.

Most location services work by looking up the registered location of your IP address or by calculating your location based off of nearby wireless access points (yes, the location of your home wifi is part of a giant database). To do these lookups, your pc is required to have an active internet connection.

Our product is designed to work just as well with and without an internet connection, so for these customers we had to find a way to make device location available to browsers without requiring an internet connection. To the surprise of no-one, browsers do not readily fetch information from hardware GPS chips/dongles. We had to create our own solution to bridge the gap between GPS hardware and the browser.

Our solution

Luckily for us, Microsoft had already done a lot of the work. Windows includes an OS level location API that many GPS devices happily register themselves with. All we had to was access it and make it available to the browser.

We decided early that creating browser plug-ins and extensions was an unacceptable solution. None of us felt like, or have the time, to maintain extensions for each of the major browsers. Nor was there any common API to directly access arbitrary system information from Windows (any technology like that would pose a huge security risk).

The solution we created out of necessity ended up being a solution we could repeat across many use cases.

We use .NET to fetch any information from Windows that we desire (Device Location in this case). We then use use .NET to create a Windows Web Service to expose that information over HTTP. Browsers can make xhr requests to this web service on localhost and receive the location data as a JSON string.

Pretty clever. We had now made nearly any Windows information available to the browser and we gladly offered the software we created to the public. https://github.com/DataSplice/locatinator

The “locatinator” worked for us for a number of years until recently Google Chrome threw us a curve-ball.

HTTPS (Hurdle #2)

Google Chrome is really doing the world a favor by enforcing security, but this particular security feature caused us some temporary headache.

First, Chrome started enforcing HTTPS security if your website/app wanted access to the device camera/fileupload api. Then they added the same enforcement for access to device location. In response, we started encouraging our customers to switch to HTTPS, either in the form of self-signed certificates within our server software, or by using secure reverse-proxies with SSL certificates provided by trusted Certificate Authorities.

Secondly, Chrome started enforcing that any site served with HTTPS can only access other sites served by HTTPS. This became a problem for our locatinator.

Our web service had always been hosted without HTTPS and we didn’t have a mechanism for securing it. From then on, HTTPS secured customer sites could no longer make requests to our GPS web service.

I took it upon myself to re-vamp our Locatinator.

EdgeJS

On Windows, we also maintain a client built with NW.JS (NW.JS is, essentially, an embedded Chrome browser with a super-powered JavaScript inferface provided by Node.JS). We have dreams about making this NW.JS client our go-to platform on Windows, but we really didn’t have any compelling features to make it attractive. Until now.

Our lead developer recommended that I look into a technology called EdgeJS. http://tjanczuk.github.io/edge/

Every person in our development team loves to stay up-to-date with the latest technology and programming concepts. EdgeJS was something our lead developer had read about but didn’t have the time to research. Having set aside the time to do so, I was able to read up on it and run through a couple of example programs. Turns out that it’s pretty slick.

EdgeJS is a set of JavaScript libraries and cross-platform binaries that allow the transfer of data between Node.JS and .NET (as well as various other languages). You can script .NET inside of Node.JS and you can script Node.JS inside of .NET. In our case, we already had the .NET capabilities, we just needed to make it available to JS so our application could consume the .NET GPS data.

To work with .NET, you can choose to write your C# code directly within your JavaScript as a function.

1
2
3
4
5
var add7 = edge.func(function() {/*
async (input) => {
return (int)input + 7;
}
*/});

Or, you can integrate with existing .NET dll libraries by calling their methods directly.

1
2
3
4
5
var clrMethod = edge.func({
assemblyFile: 'My.Edge.Samples.dll',
typeName: 'Samples.FooBar.MyType',
methodName: 'MyMethod' // This must be Func<object,Task<object>>
});

As the example above states, the .NET method must be a Function that takes any object as input and outputs a Task that provides a resulting object. This lets Node.JS execute .NET methods asynchronously.

I quickly realized that using EdgeJS is going to take care of two of our problems. EdgeJS will allow us to integrate our .NET with NW.JS without a web service, which makes our NW.JS client an attractive option for customers. To support browsers, EdgeJS will also allow us to implement our web service with Node.JS instead of C# (Setting up HTTPS on Node.JS web servers is incredibly easy).

Locatinator 2.0

Before starting to integrate with NW.JS, I wanted to focus on the locatinator web service first.

All of the code for this project is temporarily located at https://github.com/WebeWizard/ds-webservice

.NET

In the lib folder you will find the .NET code that compiles to a dll.
Most of the .NET class is just standard code, but for convenience I created a wrapper to make the class EdgeJS friendly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class EdgeGeoProvider
{
private static Locatinator winGeo = new Locatinator();
public Func<object, Task<object>> startWatcher = (Func<object, Task<object>>)(async (input) => { return winGeo.StartWatcher((string)input); });
public Func<object, Task<object>> stopWatcher = (Func<object, Task<object>>)(async (input) => { return winGeo.StopWatcher(); });
public Func<object, Task<object>> getPosition = (Func<object, Task<object>>)(async (input) => { return winGeo.GetPosition(); });
public Func<object, Task<object>> getStatus = (Func<object, Task<object>>)(async (input) => { return winGeo.GetStatus(); });
}
public class EdgeWrapper
{
public async Task<object> getProvider(object input)
{
EdgeGeoProvider provider = new EdgeGeoProvider();
return provider;
}
}

EdgeGeoProvider takes the normal locatinator class and creates a new instance of it. Without this “provider”, we wouldn’t be able to maintain state within an instance of the locatinator object.

EdgeWrapper takes the provider and wraps it in an EdgeJS friendly function. Now I only have to make one call from JavaScript to expose all of the functionality of the provider.

Node.JS

The code for Node.JS is written in CoffeeScript and then compiled to JavaScript for distribution.

I won’t post the coffeescript code here, but if you look at the Github project, you can find the code primarily in server.coffee, providers.coffee, and locatinator.coffee.

locatinator.coffee contains the integration with EdgeJS that gets ahold of the .NET provider and allows us to make calls to the provider’s methods.

providers.coffee is responsible for initializing providers and adding their sub-routes to the server route map.

server.coffee provides the Node.JS web server and serves data requested by routes.
Routes like ‘\gps\location’ are added to a route map by providers.coffee. In this case, ‘gps’ refers to the locatinator provider, and ‘location’ refers to a sub-route within that provider that serves location data.

Distribution

I decided not to use Gulp to manage builds on this project. It’s all for Windows, so there is no need to support cross-platform building and distribution. Instead I am using windows .bat files to compile the C# code, CoffeeScript code, and make a release folder.

No real hurdles here except file size. I can’t expect our customers to have a Node.JS runtime installed on their devices so I have to include one. The executable for Node.JS is about 13MB. The dependency on EdgeJS was massive, around 40MB. Digging in the EdgeJS folders I saw that a lot of the size due to edgejs including all of the different cross-platform binaries by default. Since I am only targeting Win32 and a specific version of Node, I was able to remove most of the cross-platform files from my release folder. All together the release is about 26MB and zips down to 19MB. That still seems large for just the locatinator, but as we add more types of providers to the web service, it won’t seem so bad.

I also distribute a self-signed certificate so Node.JS can provide an HTTPS secured server, which solves our Chrome problems.

Conclusion

I’m pretty proud of myself for this one. The EdgeJS friendly .NET dlls that provide Windows data to the web service are now also available to our NW.JS client, where integration should be easy.

There is still a bit of work to be done, but mostly it’s on the node.js server side. EdgeJS took all of the hard work out of integrating with Windows.

Thanks for reading!

Share Comments

Rust Recursion Practice

While working on a different project, I came across this puzzle.

Given a set of values, compute its full set of combinations.

Note that a “Combination” is a group of values where order of the values does not matter. Ex: ‘123’
We are NOT computing a set of “Permutations”. Ex: ‘123’ and ‘213’ and ‘321’ etc.

So, for example, we want to compute the set of combinations for the values 1,2,3 we can easily list them out by hand.
1, 12, 13, 14, 123, 124, 134, 1234, 2, 23, 24, 234, 3, 34, 4

There are 2^(n)-1 or 15 total combinations. Easy enough right?
What about values 1 to 5? That’s 31 combinations.
what about values 1 to 999? I’d spend the rest of my lifetime writing out that list.

How do we write a program to do this for us?

We know we need a loop for the most significant digit… and going deeper, we assume we need another loop for the second most significant digit… deeper still means more loops… MOOAARR LOOPS.

Writing 999 loops is definitely easier than writing out each combination by hand, but I still don’t want to write out 999 loops.

If we were only computing a single value result, we might think about solving this problem mathematically and avoid loops altogether. But instead, we need to record a combination at each step of the process.

The technique for solving these types of “loops on loops on loops” problems is called “Recursion”.

What recursion in programming looks like is a function, that during its execution, calls itself.

1
2
3
fn recursive_function() {
recursive_function();
}

We can use a recursive function to perform our loops within loops within loops and record a combination at each step.

Solving the problem.

Let’s start our program by defining our start and end values from the first example above.

We’ll also create a Vec that will hold our result.

1
2
3
let start = 1;
let end = 4;
let mut collection: Vec<Vec<usize>> = Vec::new();

For the meat and potatoes of our program, we need a loop that serves the purpose of “given a number, calculate all combinations of values >= this number”. Ex: Given 1, calculate 1, 12, 123, 1234, 13, etc.

1
2
3
4
5
// end+1 because Rust for-loop endings are non-inclusive
for i in start..end+1
{
// Something here will perform the computations.
}

Inside of the loop, we’ll put our recursive function… the recursive function… the recursive…

What kind of recursive function will solve this problem?

Since each call to the recursive function needs to know the part of the problem it’s supposed to work on, we need to give it the current position of the overall problem. We’ll call it pos for position. Ex. pos of ‘2’ will work on 2,23,234,24

We also need to keep track of the history of numbers that came before our recursive function call. We’ll call that history prefix. If pos is ‘3’, then prefix could be ‘1’ or ‘12’ or ‘2’.

We need to know how many times we need to repeat the inner loops ( current position to the end), so we’ll keep passing the end variable we created earlier.

Finally, we need a place to record our results from each step. We’ll pass a reference to our mutable collections vector along as well.

The code for the recursive function ends up looking like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
fn recurse( pos: usize, end: usize, mut prefix: Vec<usize>, mut collection: &mut Vec<Vec<usize>>) {
// push the current pos onto the prefix
prefix.push(pos);
// repeat the recursion for all values from pos to end
for i in pos+1..end+1 {
// we need a copy of the prefix to pass into the next recursion
let newprefix = prefix.clone();
// recurse the same function and blow our minds with convenience
recurse( i, end, newprefix, collection);
}
// for each step of recursion, push the prefix (now a combination) into the collection.
collection.push(prefix);
}

Putting it all together into a working program…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
fn main() {
let start = 1;
let end = 4;
let mut collection: Vec<Vec<usize>> = Vec::new();
for i in start..end+1
{
let prefix: Vec<usize> = Vec::new();
recurse( i, end, prefix, &mut collection );
}
println!("{:?}",collection);
}
fn recurse( pos: usize, end: usize, mut prefix: Vec<usize>, mut collection: &mut Vec<Vec<usize>>) {
prefix.push(pos);
for i in pos+1..end+1 {
let newprefix = prefix.clone();
recurse( i, end, newprefix, collection);
}
collection.push(prefix);
}

The result comes out just as we wanted. By printing the Collection we see it contains all combinations for the values 1 to 4.

1
[[1, 2, 3, 4], [1, 2, 3], [1, 2, 4], [1, 2], [1, 3, 4], [1, 3], [1, 4], [1], [2, 3, 4], [2, 3], [2, 4], [2], [3, 4], [3], [4]]

Recursive functions are great for solving these types of problems.

Warning

Because we retain and build data at each step of the recursion, we quickly consume a large amount of memory as the value of end increases.

Share Comments

Starting Hexo On Boot

  1. Create a shell script to execute the Hexo server.

    1
    2
    cd ~
    nano starthexo.sh

    The contents can be as simple as the following:

    1
    2
    3
    #!/bin/bash
    cd /path/to/hexo/workspace
    hexo server
  2. Make the script executable.

    1
    chmod u+x starthexo.sh
  3. Edit your user’s crontab file to start Hexo on boot.

    1
    crontab -u myusername -e

    Add the following line to the bottom of your crontab file.

    1
    @reboot sh starthexo.sh
Share Comments

Let's try this blogging thing again

Remember that time I tried to run a wordpress site and GoDaddy locked me out of my own database over and over? Good times… Such fun…

This time we’re doing it ourselves. DigitalOcean hosted server, nodejs, Hexo blogging engine, and git. No databases, no bloated webserver. Just my thoughts, written in markdown, and a command line.

And because googling for “hexo startup at boot” apparently returns bollocks… I suppose that will be my first post. Thank you Hexo. You’re welcome Hexo community.

Share Comments