Skip to content

Commit

Permalink
Added a Demo Server + Client in .NET + first Release!
Browse files Browse the repository at this point in the history
  • Loading branch information
floriansegginger committed Oct 7, 2015
1 parent d81030c commit 349719c
Show file tree
Hide file tree
Showing 19 changed files with 631 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
bin
obj
/*.suo
Binary file added Release/DotNet/Woopsa.dll
Binary file not shown.
Binary file added Release/DotNet/Woopsa.pdb
Binary file not shown.
Binary file added Release/DotNet/WoopsaDemoClient.exe
Binary file not shown.
Binary file added Release/DotNet/WoopsaDemoServer.exe
Binary file not shown.
213 changes: 213 additions & 0 deletions Release/JavaScript/woopsa-client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
(function (global){
var nop = function () {};

var Subscription = function (channel, path, onChangeCallback, successCallback, monitorInterval, publishInterval) {
this.channel = channel;
this.path = path;
this.onChange = onChangeCallback || nop;

this.subscriptionId = null;

monitorInterval = monitorInterval || 100;
publishInterval = publishInterval || 200;
successCallback = successCallback || nop;

this.unregister = function (successCallback) {
return channel.client.invoke(
"/SubscriptionService/UnregisterSubscription",
{
SubscriptionChannel: channel.channelId,
SubscriptionId: this.subscriptionId
},
(function (result) {
successCallback();
}).bind(this)
);
}

this.register = function (callback){
return channel.client.invoke(
"/SubscriptionService/RegisterSubscription",
{
SubscriptionChannel: channel.channelId,
PropertyLink: path,
MonitorInterval: monitorInterval,
PublishInterval: publishInterval
},
(function (result) {
this.subscriptionId = result;
successCallback();
if ( callback ){
callback(this);
}
}).bind(this)
);
}

this.register.call(this);
};

var SubscriptionChannel = function (client, notificationQueueSize, onCreateCallback) {
this.client = client;
this.onCreate = onCreateCallback;

this.channelId = null;
this.subscriptions = [];
this.listenStarted = false;
this.subscriptionsDictionary = {};

var created = false;

this.registerSubscription = function (path, onChangeCallback, successCallback, monitorInterval, publishInterval) {
var newSubscription = new Subscription(this, path, onChangeCallback, successCallback, monitorInterval, publishInterval);
this.subscriptions.push(newSubscription);
if ( !this.listenStarted ) {
this.listenStarted = true;
waitNotification.call(this);
}
this.subscriptionsDictionary[path] = newSubscription;
return newSubscription;
};

this.unregisterSubscription = function (subscription, successCallback) {
var subscriptionIndex = this.subscriptions.indexOf(subscription);
if ( subscriptionIndex != -1 ) {
this.subscriptions[subscriptionIndex].unregister((function (subscriptionIndex, successCallback){
this.subscriptions.splice(subscriptionIndex, 1);
successCallback();
}).bind(this, subscriptionIndex, successCallback))
}
}

this.register = function (){
return client.invoke(
"/SubscriptionService/CreateSubscriptionChannel",
{NotificationQueueSize: notificationQueueSize},
(function (result){
this.channelId = result;
if ( !created )
this.onCreate.call(this, this.channelId);
created = true;
}).bind(this)
);
}

this.register.call(this);

var retryFrequency = 10000; //The frequency at which to retry connecting, in milliseconds

var waitNotification = function () {
return client.invoke(
"/SubscriptionService/WaitNotification",
{SubscriptionChannel: this.channelId},
(function (notifications) {
for ( var i = 0; i < notifications.length; i++ ) {
var notification = notifications[i];
if ( this.subscriptionsDictionary[notification.PropertyLink.Value] ) {
this.subscriptionsDictionary[notification.PropertyLink.Value].onChange(notification.Value.Value);
}
}
waitNotification.call(this);
}).bind(this)
).fail(function (request, status, error){
if ( request.readyState == 4 ){
//We have reconnected but the server has forgotten our channel
this.register().done(function (){
for ( var i = 0; i < this.subscriptions.length; i++ ) {
this.subscriptions[i].register()
}
}.bind(this))
}
setTimeout((function (){
waitNotification.call(this);
}).bind(this), retryFrequency);
}.bind(this));
}
};

global.WoopsaClient = function (url, jQuery) {
var $ = jQuery;
var subscriptionChannel = null;
var errorCallbacks = [];

if ( url.lastIndexOf('/') == url.length-1 ) {
this.url = url;
} else {
this.url = url + "/";
}

this.read = function (path, callback) {
return $.get(this.url + "read" + path, {}, function (data, textStatus, jqXHR) {
callback(data.Value, path);
}).fail(function (request, status, errorThrown){
raiseError(status, errorThrown);
});
};

this.write = function (path, value, callback) {
return $.post(this.url + "write" + path, {value: value}, function (data, textStatus, jqXHR) {
callback(true, path);
})
.fail(function (request, status, errorThrown){
raiseError(status, errorThrown);
});
};

this.meta = function (path, callback) {
return $.get(this.url + "meta" + path, {}, function (data, textStatus, jqXHR) {
callback(data, path);
})
.fail(function (request, status, errorThrown){
raiseError(status, errorThrown);
});
};

this.invoke = function (path, arguments, callback, timeout) {
timeout = timeout || 10000;
return $.ajax({
type: 'POST',
timeout: timeout,
url: this.url + "invoke" + path,
data: arguments
})
.done(function (data){
callback(data.Value);
})
.fail(function (request, status, errorThrown){
raiseError(status, errorThrown);
});
};

this.createSubscriptionChannel = function (notificationQueueSize, callback) {
if ( subscriptionChannel != null ) {
callback.call(subscriptionChannel, subscriptionChannel.channelId);
return;
}
var newChannel = new SubscriptionChannel(this, notificationQueueSize, function (channelId){
callback.call(this, channelId);
})
subscriptionChannel = newChannel;
return newChannel;
};

this.onChange = function (path, callback, monitorInterval, publishInterval) {
if ( subscriptionChannel == null ) {
this.createSubscriptionChannel(200, (function (){
this.onChange(path, callback, monitorInterval, publishInterval);
}).bind(this))
}else{
subscriptionChannel.registerSubscription(path, callback, nop, monitorInterval, publishInterval);
}
};

this.onError = function (callback){
errorCallbacks.push(callback);
};

function raiseError(type, errorThrown){
for ( var i = 0; i < errorCallbacks.length; i++ ) {
errorCallbacks[i](type, errorThrown);
}
}
};
})(window);
1 change: 1 addition & 0 deletions Release/JavaScript/woopsa-client.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Woopsa/build-windows.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
devenv ..\Woopsa.sln /build Release /project Woopsa
6 changes: 6 additions & 0 deletions WoopsaDemoClient/App.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
96 changes: 96 additions & 0 deletions WoopsaDemoClient/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using Woopsa;

namespace WoopsaDemoClient
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(" *** Welcome to the Woopsa Demo Client! *** ");
Console.WriteLine(" Note: read the source code to understand what's happening behind the scenes!");
Console.WriteLine("");
Console.Write("Please enter the Woopsa server URL or leave blank for default (http://localhost/woopsa): ");

string serverUrl = Console.ReadLine();
if (serverUrl == "")
serverUrl = "http://localhost/woopsa";

WoopsaClient client = new WoopsaClient(serverUrl);

Console.WriteLine("Woopsa client created on URL: {0}", serverUrl);

// Display all properties and their values
Console.WriteLine("Properties and their values:");
foreach (WoopsaClientProperty property in client.Root.Properties)
{
Console.WriteLine(" * {0} : {1} = {2}", property.Name, property.Type, property.Value);

// As an example, if we find a PropertyInteger value (like in the demo server),
// we change its value to 1. That way you can see how it's done using the
// standard client
if (property.Name == "PropertyInteger")
{
// Create a subscription for example's sake
Console.WriteLine(" => Creating a subscription");
property.Change += property_Change;

// Actually change the value
Console.WriteLine(" => Changing value to 1");
property.Value = new WoopsaValue(1);
}
}

// Display methods and their arguments
Console.WriteLine("Methods and their arguments:");
foreach (WoopsaMethod method in client.Root.Methods)
{
// Display the method
Console.WriteLine(" * {0} : {1}", method.Name, method.ReturnType);
foreach (WoopsaMethodArgumentInfo argumentInfo in method.ArgumentInfos)
{
Console.WriteLine(" * {0} : {1}", argumentInfo.Name, argumentInfo.Type);
}

// As an example, if we find a SayHello method (like in the demo server),
// we call it. That way you can see how to call methods using the standard
// client!
if (method.Name == "SayHello")
{
Console.WriteLine(" => SayHello found! Calling it now...");
Console.WriteLine(" => Result = {0}", method.Invoke(new List<IWoopsaValue>()
{
new WoopsaValue("Woopsa Demo Client")
})
);
}
}

// Display embedded items and display its properties
Console.WriteLine("Items:");
foreach (WoopsaClientObject item in client.Root.Items)
{
// Display the item
Console.WriteLine(" * {0}", item.Name);

foreach(WoopsaClientProperty property in item.Properties)
{
Console.WriteLine(" * {0} : {1} = {2}", property.Name, property.Type, property.Value);
}
}

// Leave the DOS window open
Console.WriteLine("Press any key to exit...");
Console.ReadLine();

// Exit gracefully
client.Dispose();
}

static void property_Change(object sender, WoopsaNotificationEventArgs e)
{
Console.WriteLine("Property {0} has changed, new value = {1}", (sender as WoopsaClientProperty).Name, e.Value);
}
}
}
36 changes: 36 additions & 0 deletions WoopsaDemoClient/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("WoopsaDemoClient")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("WoopsaDemoClient")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f2bd77d7-5671-4d9b-94ab-8c1a5c16168b")]

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
Loading

0 comments on commit 349719c

Please sign in to comment.