my company choose "Mercure" (https://mercure.rocks/docs/getting-started) to manage Server-Sent Events.
We install "Mercure HUB" on a server and now, in C# .NET 5.0, I must implement the server-side (publisher, that I already implemented) and the client-side (subscriber).
The subscriber must be done with a WPF
From the "getting-started" page I can see a Javascript example that I need to transform into C#
I don't know how to manage a "EventSource" in C#
Any ideas ?
// The subscriber subscribes to updates for the https://example.com/users/dunglas topic
// and to any topic matching https://example.com/books/{id}
const url = new URL('https://localhost/.well-known/mercure');
url.searchParams.append('topic', 'https://example.com/books/{id}');
url.searchParams.append('topic', 'https://example.com/users/dunglas');
// The URL class is a convenient way to generate URLs such as https://localhost/.well-known/mercure?topic=https://example.com/books/{id}&topic=https://example.com/users/dunglas
const eventSource = new EventSource(url);
// The callback will be called every time an update is published
eventSource.onmessage = e => console.log(e); // do something with the payload
The code of this page works (https://makolyte.com/event-driven-dotnet-how-to-consume-an-sse-endpoint-with-httpclient/)
static async Task Main(string[] args)
{
HttpClient client = new HttpClient();
client.Timeout = TimeSpan.FromSeconds(5);
string stockSymbol = "VTSAX";
string url = $"http://localhost:9000/stockpriceupdates/{stockSymbol}";
while (true)
{
try
{
Console.WriteLine("Establishing connection");
using (var streamReader = new StreamReader(await client.GetStreamAsync(url)))
{
while (!streamReader.EndOfStream)
{
var message = await streamReader.ReadLineAsync();
Console.WriteLine($"Received price update: {message}");
}
}
}
catch(Exception ex)
{
//Here you can check for
//specific types of errors before continuing
//Since this is a simple example, i'm always going to retry
Console.WriteLine($"Error: {ex.Message}");
Console.WriteLine("Retrying in 5 seconds");
await Task.Delay(TimeSpan.FromSeconds(5));
}
}
}
Related
With ajax requests it can be done with this code:
let oldXHROpen = window.XMLHttpRequest.prototype.open;
window.lastXhr = '';
window.XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
this.addEventListener('load', function() {
window.lastXhr = this.responseText;
});
return oldXHROpen.apply(this, arguments);
};
lastXhr variable will hold the last response.
But how can this be achieved for websockets too?
you would need to make this wrapper as soon as possible
#brunoff you're correct in that you can always use your functions before a server's by puppet window logic, or you could just hijack the data from the MessageEvent itself:
function listen(fn){
fn = fn || console.log;
let property = Object.getOwnPropertyDescriptor(MessageEvent.prototype, "data");
const data = property.get;
// wrapper that replaces getter
function lookAtMessage() {
let socket = this.currentTarget instanceof WebSocket;
if (!socket) {
return data.call(this);
}
let msg = data.call(this);
Object.defineProperty(this, "data", { value: msg } ); //anti-loop
fn({ data: msg, socket:this.currentTarget, event:this });
return msg;
}
property.get = lookAtMessage;
Object.defineProperty(MessageEvent.prototype, "data", property);
}
listen( ({data}) => console.log(data))
You can try putting in the code and running it in the console on this page and then running their WebSocket example.
To intercept the messages, you will have to spy on the onmessage = fn and addEventListener("message", fn) calls.
To be able to modify the onmessage we have to override the global WebSocket in the first place. The below is intercepting the incoming messages, but in a similar way you can spy on the send method to intercept the outgoing messages (the ones sent by the client to the server).
I tested this on a page using Firebase and it works nicely, but you have to initialize it before the other scripts making sure that the websocket library (it can be socket.io, ws, etc) is using the overridden WebSocket constructor.
Spy the Incoming Messages and modify the data
Eventually you can override the data before calling the real message listener – this becomes handy if you do not have control over the page functionality and want to inject your own data in the message listener.
const OriginalWebsocket = window.WebSocket
const ProxiedWebSocket = function() {
console.log("Intercepting web socket creation")
const ws = new OriginalWebsocket(...arguments)
const originalAddEventListener = ws.addEventListener
const proxiedAddEventListener = function() {
if (arguments[0] === "message") {
const cb = arguments[1]
arguments[1] = function() {
// Here you can get the actual data from the incoming messages
// Here you can even change the data before calling the real message listener
Object.defineProperty(e, "data", { value: 'your injected data' })
console.log("intercepted", arguments[0].data)
return cb.apply(this, arguments)
}
}
return originalAddEventListener.apply(this, arguments)
}
ws.addEventListener = proxiedAddEventListener
Object.defineProperty(ws, "onmessage", {
set(func) {
return proxiedAddEventListener.apply(this, [
"message",
func,
false
]);
}
});
return ws;
};
window.WebSocket = ProxiedWebSocket;
If you do not need to modify the data, you can follow the second part of the answer.
Spy the Incoming messages without modifying the data
If you want to listen for messages only, without overriding the data, things are simpler:
const OriginalWebsocket = window.WebSocket
const ProxiedWebSocket = function() {
const ws = new OriginalWebsocket(...arguments)
ws.addEventListener("message", function (e) {
// Only intercept
console.log(e.data)
})
return ws;
};
window.WebSocket = ProxiedWebSocket;
Spy the Outgoing Messages
In a very similar way, you can proxy the send method which is used to send data to the server.
const OriginalWebsocket = window.WebSocket
const ProxiedWebSocket = function() {
const ws = new OriginalWebsocket(...arguments)
const originalSend = ws.send
const proxiedSend = function() {
console.log("Intercepted outgoing ws message", arguments)
// Eventually change the sent data
// arguments[0] = ...
// arguments[1] = ...
return originalSend.apply(this, arguments)
}
ws.send = proxiedSend
return ws;
};
window.WebSocket = ProxiedWebSocket;
Feel free to ask any questions if anything is unclear.
In a solution similar to yours, where the window.XMLHttpRequest was replaced with a wrapped version that feeds window.lastXhr, we replace window.WebSockets with a wrapped version that feeds window.WebSocketMessages with all messages and timestamps received from all websockets created after this script.
window.watchedWebSockets = [];
window.WebSocketMessages = [];
function WebSocketAttachWatcher(websocket) {
websocket.addEventListener("message", (event)=>window.WebSocketMessages.push([event.data,Date.now()]));
window.watchedWebSockets.push(websocket);
}
// here we replace WebSocket with a wrapped one, that attach listeners on
window.WebSocketUnchanged = window.WebSocket;
window.WebSocket = function(...args) {
const websocket = new window.WebSocketUnchanged(...args);
WebSocketAttachWatcher(websocket);
return websocket;
}
Differently from your XMLRequest case, the websocket may already exist. If you need garanties that all websockets would be catched then you would need to make this wrapper as soon as possible. If you just can't, there's an not so good trick to capture already existing websockets once they send a message:
// here we detect existing websockets on send event... not so trustable
window.WebSocketSendUnchanged = window.WebSocketUnchanged.prototype.send;
window.WebSocket.prototype.send = function(...args) {
console.log("firstsend");
if (!(this in window.watchedWebSockets))
WebSocketAttachWatcher(this);
this.send = window.WebSocketSendUnchanged; // avoid passing here again on next send
window.WebSocketSendUnchanged.call(this, ...args);
}
It is not so trustable since if they don't send but receive they will stay unnoticed.
Intro
The question/bounty/op is specifically asking for a reputable source.
Instead of rolling a custom solution, my proposal is that a known proven library should be used - that has been used, audited, forked, and in general used by the community and that is hosted on github.
The second option is to roll your own (though not recommended) and there are many exccelent answers on how to do it involving the addEventListener
wshook
Wshook is a library (hosted on github) that allows to easily intercept and modify WebSocket requests and message events. It has been starred and forked multiple times.
Disclaimer: I don't have any relationship with the specific project.strong text
Example:
wsHook.before = function(data, url, wsObject) {
console.log("Sending message to " + url + " : " + data);
}
// Make sure your program calls `wsClient.onmessage` event handler somewhere.
wsHook.after = function(messageEvent, url, wsObject) {
console.log("Received message from " + url + " : " + messageEvent.data);
return messageEvent;
}
From the documentation, you will find:
wsHook.before - function(data, url, wsObject):
Invoked just before
calling the actual WebSocket's send() method.
This method must return data which can be modified as well.
wsHook.after - function(event, url, wsObject):
Invoked just after
receiving the MessageEvent from the WebSocket server and before
calling the WebSocket's onmessage Event Handler.
Websocket addEventListener
The WebSocket object supports .addEventListener().
Please see: Multiple Handlers for Websocket Javascript
if you are using nodejs then you can use socket.io
yarn add socket.io
after installation, you can use the middleware of socket.io
io.use(async (socket, next) => {
try {
const user = await fetchUser(socket);
socket.user = user;
} catch (e) {
next(new Error("unknown user"));
}
});
I am fairly new to JS/Winappdriver.
The application I am trying to test is a windows based "Click Once" application from .Net, so I have to go to a website from IE and click "Install". This will open the application.
Once the application is running, I have no way to connect the application to perform my UI interactions while using JavaScript.
Using C#, I was looping through the processes looking for a process name, get the window handle, convert it to hex, add that as a capability and create the driver - it worked. Sample code below,
public Setup_TearDown()
{
string TopLevelWindowHandleHex = null;
IntPtr TopLevelWindowHandle = new IntPtr();
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.StartsWith($"SomeName-{exec_pob}-{exec_env}"))
{
TopLevelWindowHandle = clsProcess.Handle;
TopLevelWindowHandleHex = clsProcess.MainWindowHandle.ToString("x");
}
}
var appOptions = new AppiumOptions();
appOptions.AddAdditionalCapability("appTopLevelWindow", TopLevelWindowHandleHex);
appOptions.AddAdditionalCapability("ms:experimental-webdriver", true);
appOptions.AddAdditionalCapability("ms:waitForAppLaunch", "25");
AppDriver = new WindowsDriver<WindowsElement>(new Uri(WinAppDriverUrl), appOptions);
AppDriver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(60);
}
How do I do this in Javascript ? I can't seem to find any code examples.
Based on an example from this repo, I tried the following in JS to find the process to latch on to but without luck.
import {By2} from "selenium-appium";
// this.appWindow = this.driver.element(By2.nativeAccessibilityId('xxx'));
// this.appWindow = this.driver.element(By2.nativeXpath("//Window[starts-with(#Name,\"xxxx\")]"));
// this.appWindow = this.driver.elementByName('WindowsForms10.Window.8.app.0.13965fa_r11_ad1');
// thisappWindow = this.driver.elementByName('xxxxxxx');
async connectAppDriver(){
await this.waitForAppWindow();
var appWindow = await this.appWindow.getAttribute("NativeWindowHandle");
let hex = (Number(ewarpWindow)).toString(16);
var currentAppCapabilities =
{
"appTopLevelWindow": hex,
"platformName": "Windows",
"deviceName": "WindowsPC",
"newCommandTimeout": "120000"
}
let driverBuilder = new DriverBuilder();
await driverBuilder.stopDriver();
this.driver = await driverBuilder.createDriver(currentEwarpCapabilities);
return this.driver;
}
I keep getting this error in Winappdriver
{"status":13,"value":{"error":"unknown error","message":"An unknown error occurred in the remote end while processing the command."}}
I've also opened this ticket here.
It seems like such an easy thing to do, but I couldn't figure this one out.
Any of nodes packages I could use to get the top level window handle easily?
I am open to suggestions on how to tackle this issue while using JavaScript for Winappdriver.
Hope this helps some one out there,
Got around this by creating an exe using C# that generated hex of the app to connect based on the process name, it looks like something like this.
public string GetTopLevelWindowHandleHex()
{
string TopLevelWindowHandleHex = null;
IntPtr TopLevelWindowHandle = new IntPtr();
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.StartsWith(_processName))
{
TopLevelWindowHandle = clsProcess.Handle;
TopLevelWindowHandleHex = clsProcess.MainWindowHandle.ToString("x");
}
}
if (!String.IsNullOrEmpty(TopLevelWindowHandleHex))
return TopLevelWindowHandleHex;
else
throw new Exception($"Process: {_processName} cannot be found");
}
Called it from JS to get the hex of the top level window handle, like this,
async getHex () {
var pathToExe =await path.join(process.cwd(), "features\\support\\ProcessUtility\\GetWindowHandleHexByProcessName.exe");
var pathToDir =await path.join(process.cwd(), "features\\support\\ProcessUtility");
const result = await execFileSync(pathToExe, [this.processName]
, {cwd: pathToDir, encoding: 'utf-8'}
, async function (err, data) {
console.log("Error: "+ err);
console.log("Data(hex): "+ data);
return JSON.stringify(data.toString());
});
return result.toString().trim();
}
Used the hex to connect to the app like this,
async connectAppDriver(hex) {
console.log(`Hex received to connect to app using hex: ${hex}`);
const currentAppCapabilities=
{
"browserName": '',
"appTopLevelWindow": hex.trim(),
"platformName": "Windows",
"deviceName": "WindowsPC",
"newCommandTimeout": "120000"
};
const appDriver = await new Builder()
.usingServer("http://localhost:4723/wd/hub")
.withCapabilities(currentAppCapabilities)
.build();
await driver.startWithWebDriver(appDriver);
return driver;
}
Solution:
In WebDriverJS (used by selenium / appium), use getDomAttribute instead of getAttribute. Took several hours to find :(
element.getAttribute("NativeWindowHandle")
POST: /session/270698D2-D93B-4E05-9FC5-3E5FBDA60ECA/execute/sync
Command not implemented: POST: /session/270698D2-D93B-4E05-9FC5-3E5FBDA60ECA/execute/sync
HTTP/1.1 501 Not Implemented
let topLevelWindowHandle = await element.getDomAttribute('NativeWindowHandle')
topLevelWindowHandle = parseInt(topLevelWindowHandle).toString(16)
GET /session/DE4C46E1-CC84-4F5D-88D2-35F56317E34D/element/42.3476754/attribute/NativeWindowHandle HTTP/1.1
HTTP/1.1 200 OK
{"sessionId":"DE4C46E1-CC84-4F5D-88D2-35F56317E34D","status":0,"value":"3476754"}
and topLevelWindowHandle have hex value :)
I am using nativescript to build an app that will programmatically send a pre-built text to multiple preset parties in case of emergency.
I have an array of phone numbers and want to iterate over each one, using SMSmanager to send the text and the sentIntent argument seen in android docs to verify that the text was sent before moving on to the next array item.
I have created the pendingIntent variable to pass into "sms.sendTextMessage" as follows:
var sms = android.telephony.SmsManager.getDefault();
var utils = require("utils/utils");
//Gets application's current state
var context = utils.ad.getApplicationContext();
//Create a replica of Android's intent object
var intent = new android.content.Intent(context, com.tns.NativeScriptActivity.class);
//Create a replica of Android's pendingIntent object using context and intent
var pendingIntent = android.app.PendingIntent.getActivity(context, 1, intent, android.app.PendingIntent.FLAG_UPDATE_CURRENT);
I then send the text, passing in the pending intent var:
sms.sendTextMessage("5555555555", null, "hello", pendingIntent, null);
I then attempt to make a basic broadcast receiver using the information I found in the nativescript docs which should just log something to the console when it recieves the expected data.
app.android.registerBroadcastReceiver(pendingIntent, function() {
console.log("##### text sent #####");
});
The problem is: nothing happens. I'd expect to get ""##### text sent #####" logged to the console. I've googled a lot and am thinking maybe I need to add something about this broadcast reciever in the manifest, or perhaps my implimentation is wrong somewhere, but this is my first crack at an android app and I'm at a bit of a loss. Any help would be appreciated.
I'm going to answer my own question here in case anyone else runs into this.
The code that worked is:
var app = require("application");
var utils = require("utils/utils");
var context = utils.ad.getApplicationContext();
var sms = android.telephony.SmsManager.getDefault();
var SendMessages = {
init: function() {
var id = "messageSent";
this.sendText(id, this.pendingIntent(id));
},
sendText: function(id, pendingIntent) {
sms.sendTextMessage("5555555555", null, "Hello :)", pendingIntent, null);
this.broadcastReceiver(id, function() {
console.log("$$$$$ text sent $$$$$");
});
},
pendingIntent: function(id) {
var intent = new android.content.Intent(id);
return android.app.PendingIntent.getBroadcast(context, 0, intent, 0);
},
broadcastReceiver: function(id, callback) {
app.android.registerBroadcastReceiver(id, function() {
callback();
});
}
};
module.exports = SendMessages;
To explain: it seems as #Mike M mentioned each intent object needs some string as an id.
Then to make the "pendingIntent" object, again as #Mike M. mentioned I needed to hook to "getBroadcast" method, then I needed to pass pending intent the app context as the first argument, then 0, then the intent object with the id.
The pending intent then is receivable in a simple broadcast receiver function by simply passing the intent id as the first argument and the callback as the second. I've tested and it's working perfectly.
Following is a simplified version, no bs code approach to what you need to make it run. You need permissions and to make sure the user accepts those permissions. This is also one of the two ways (this one is the context-registered receiver way) to create a broadcast receiver, read more about both types here: https://developer.android.com/guide/components/broadcasts#receiving-broadcasts
Info on registering broadcast receiver: https://docs.nativescript.org/api-reference/classes/application.androidapplication.html#registerbroadcastreceiver
AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="__PACKAGE__"
android:versionCode="10000"
android:versionName="1.0">
<!-- ...more code -->
<uses-permission android:name="android.permission.SEND_SMS" />
<!-- ...more code -->
</manifest>
JavaScript:
import * as application from 'tns-core-modules/application';
import * as platform from 'tns-core-modules/platform';
import * as utils from 'tns-core-modules/utils/utils';
import * as permissions from 'nativescript-permissions';
// ...more code
try {
await permissions.requestPermission(
android.Manifest.permission.SEND_SMS,
'Need to send.'
);
console.log('SEND_SMS permission accepted.');
const text = 'Herro.';
const mobileNumber = '55555555';
const intentFilter = 'something_here';
const context = utils.ad.getApplicationContext();
const intent = new android.content.Intent(intentFilter);
const pendingIntent = android.app.PendingIntent.getBroadcast(context, 0, intent, 0);
const sms = android.telephony.SmsManager.getDefault();
application.android.registerBroadcastReceiver(intentFilter, function() {
console.log(`Text has been sent: ${text}`);
});
setTimeout(() => {
console.log('Sending text.');
sms.sendTextMessage(mobileNumber, null, text, pendingIntent, null);
}, 5000);
} catch (error) {
console.log('Permission error:', error);
}
The code above is created inside the activity and uses the main ui thread. This means that if the user exits the activity, the broadcast receiver will linger in limbo and android can destroy it.
I have an application built with AngularJS and .NET Web API that uses Http Basic Authentication for security. They're on different subdomains eg: mydomain.com & api.mydomain.com
I have a secure url on the web api 'https://api.mydomain.com/downloadFile' that generates an excel file that I need to download on the client. I tried getting the file to download through angularjs using HTML5 Blob objects but kept getting 'File corrupt' error messages when the file tried to open.
The solution I came up with was to create a hidden iframe for downloading the file
<iframe style="display:none;" ng-src="{{downloadFileUrl}}"></iframe>
And setting $scope.downloadFileUrl in the controller
$scope.downloadFile = function () {
$scope.downloadFileUrl = $sce.trustAsResourceUrl('https://api.mydomain.com/downloadFile');
};
This works but I'm forced to log in to the api again because the HTTP 'Authorization' header isn't being sent as part of the request from the iframe. Is there a way to pass the 'Authorization' header with the request from the iframe or any other way to securely download a file from the server without having to log in again?
I use the iframe download method as well. It seems the most solid cross-browser supported method of downloading. So I agree with your method here.
I don't think you can pass headers, I've looked for it as well. And unless I have somehow totally missed a way of doing that (not unthinkable) I believe it just can't be done.
I have solved this by using tickets. Here's how: whenever data is show that can be downloaded I generate a ticket on the server based on the primary key of the file to be downloaded (a guid in my case). This ticket is a simple random string of a few characters and is stored somewhere (just the db in my case). It had an expiration time of 10 minutes. Which means, clicking the download url with the ticket in the querystring will log you in automatically and start your download. The ticket expires after a absolute expiration, user explicit logout or when the download was completed successfully.
Like so:
https://api.mydomain.com/downloadFile/{fileId}?ticket=fk37cltps7
The advice in this thread (question and answer) proved invaluable, and I thought I would put up some code implementing the advice as it may speed someone up in the future
internal const string DownloadPurpose ="FileDownload";
[Route("GenerateDownloadToken")]
public async Task<IHttpActionResult> GenerateDownloadToken()
{
var userId = Guid.Parse(User.Identity.GetUserId());
var t = await UserManager.GenerateUserTokenAsync(DownloadPurpose, userId);
return Ok(t);
}
private async Task<bool> VerifyUserTokenAsync(string token, Guid userId)
{
var returnVar = await UserManager.VerifyUserTokenAsync(userId, AccountController.DownloadPurpose, token, TimeSpan.FromMinutes(1));
if (returnVar && !User.Identity.IsAuthenticated)
{
//for using the logic to restrict access within our Dto layer
var appUser = await UserManager.FindByIdAsync(userId);
//hopefully changing this will not cause problems downstream - we do not want cookies going back and forward
User = new RequestOnlyPrincipal(appUser.UserName, await UserManager.GetRolesAsync(userId));
}
return returnVar;
}
public static class TimeSpanTokenExtensions
{
//a bit of a hack really
public static async Task<bool> VerifyUserTokenAsync<TUser, TKey>(this UserManager<TUser, TKey> manager, TKey userId, string purpose, string token, TimeSpan tokenLifeSpan)
where TUser : class, IUser<TKey>
where TKey : IEquatable<TKey>
{
var provider = (DataProtectorTokenProvider<TUser, TKey>)manager.UserTokenProvider;
TimeSpan defaultSpan = provider.TokenLifespan;
provider.TokenLifespan = tokenLifeSpan;
var returnVar = await manager.VerifyUserTokenAsync(userId, purpose, token);
provider.TokenLifespan = defaultSpan;
return returnVar;
}
}
private List<Stream> _streamsToDispose = new List<Stream>();
[Route("ScenarioResources")]
[HttpGet]
public async Task<HttpResponseMessage> GetResourcesForScenario([FromUri]DowloadFileSetModel model)
{
if (!ModelState.IsValid)
{
return Request.CreateResponse(HttpStatusCode.BadRequest, ModelState);
}
if (!await VerifyUserTokenAsync(model.Token, model.UserId))
{
return Request.CreateResponse(HttpStatusCode.Unauthorized);
}
//logic here to test the specific user has the required access rights
var path = //logic to obtain path here, using properties of model
FileStream stream = new FileStream(path, FileMode.Open);
_streamsToDispose.Add(stream);
var result = new HttpResponseMessage()
{
Content = new StreamContent(stream)
};
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "easy to read.xls"//suggested filename
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentLength = stream.Length;
return result;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_streamsToDispose.ForEach(s=>s.Dispose());
}
base.Dispose(disposing);
}
public class DowloadFileSetModel
{
[Required]
public Guid EntitySetId { get; set; }
[Required]
public Guid UserId { get; set; }
[Required]
public string Token { get; set; }
}
and the JS
function downloadFileLink(actionName, entitySetId) {
return $http({
method: 'POST', //specify post so as not to cache etc
url: 'api/Account/GenerateDownloadToken'
}).then(function (response) {
var params = {
EntitySetId: entitySetId,
Token: response.data,
UserId: tokenStorageService.getUserId()
};
var location = window.location.origin + '/api/utilities/' + actionName
+ '?' + $httpParamSerializerJQLike(params);
return $sce.trustAsResourceUrl(location);
}, log.error);
}
Can the following VB Script to open an IP cash drawer be done in Javascript instead?
Private Sub CashDrawerConnect_Click()
Winsock1.Close
ipaddr = "192.168.2.5"
Winsock1.RemoteHost = ipaddr
Winsock1.RemotePort = 30998
Winsock1.Connect
Sleep 250
TxtOpStatus = "Connection to the cash drawer at " & ipaddr & " is established..."
TxtOpStatus.Refresh
End Sub
Private Sub CashDrawerOpen_Click()
If Winsock1.State = sckConnected Then
Winsock1.SendData "opendrawer\0a"
Else
TxtOpStatus = "Not connected to the device"
TxtOpStatus.Refresh
End If
End Sub
You could do it on javascript, but not while running on a browser.
You would need to install nodejs and run your js file directly from the console.
This is a small example that would connect you the the drawer and send the "opendrawer" command on your example:
var net = require('net');
var client = net.connect({port: 30998, host: "yourip"}, function() {
client.write("opendrawer\0a");
});
If however the server has access to the drawer the javascript code could just make a request to the server which would be on charge of opening the connection to the drawer and sending the payload (opendrawer).
If you use php you can take a look at the sockets documentation.
Using VB and JavaScript the calls are mostly the same, you just jhave to adapt it to the language. http://www.ostrosoft.com/oswinsck/oswinsck_javascript.asp
The following is a snippet that uses WinSock from JScript
var oWinsock;
var sServer = "192.168.2.5";
var nPort = 3098;
var bClose = false;
oWinsock = new ActiveXObject("OSWINSCK.Winsock");
// Hooking up handlers
WScript.ConnectObject(oWinsock, "oWinsock_");
oWinsock.Connect(sServer, nPort);
WScript.Echo("Invalid URL");
bClose = true;
function oWinsock_OnConnect() {
oWinsock.SendData('Your data');
}
function oWinsock_OnDataArrival(bytesTotal) {
var sBuffer = oWinsock.GetDataBuffer();
sSource = sSource + sBuffer;
}
function oWinsock_OnError(Number, Description, Scode, Source,
HelpFile, HelpContext, CancelDisplay) {
WScript.Echo(Number + ': ' + Description);
}
function oWinsock_OnClose() {
oWinsock.CloseWinsock();
WScript.Echo(sSource);
oWinsock = null;
bClose = true;
}
while (!bClose) {
WScript.Sleep(1);
}
In the browser? Not really, but you can use WebSockets http://en.wikipedia.org/wiki/WebSocket
You'll need to implement a WebSocket server, so if you need to talk directly to a socket, you can't do it from a browser. But you could implement a proxy server that relays information between the socket server and the WebSocket server.
If you don't need two way communication, the best thing would be for your server to provide a webservice that wraps that socket request. Then your client can just make an AJAX call.