Client always responding to previous server-sent event, not current event - javascript

I am seeing odd behavior with the code here.
Client-side (Javascript):
<input type="text" id="userid" placeholder="UserID" /><br />
<input type="button" id="ping" value="Ping" />
<script>
var es = new EventSource('/home/message');
es.onmessage = function (e) {
console.log(e.data);
};
es.onerror = function () {
console.log(arguments);
};
$(function () {
$('#ping').on('click', function () {
$.post('/home/ping', {
UserID: parseInt($('#userid').val()) || 0
});
});
});
</script>
Server-side (C#):
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Web.Mvc;
using Newtonsoft.Json;
namespace EventSourceTest2.Controllers {
public class PingData {
public int UserID { get; set; }
public DateTime Date { get; set; } = DateTime.Now;
}
public class HomeController : Controller {
public ActionResult Index() {
return View();
}
static ConcurrentQueue<PingData> pings = new ConcurrentQueue<PingData>();
public void Ping(int userID) {
pings.Enqueue(new PingData { UserID = userID });
}
public void Message() {
Response.ContentType = "text/event-stream";
do {
PingData nextPing;
if (pings.TryDequeue(out nextPing)) {
var msg = "data:" + JsonConvert.SerializeObject(nextPing, Formatting.None) + "\n\n";
Response.Write(msg);
}
Response.Flush();
Thread.Sleep(1000);
} while (true);
}
}
}
Once I've pressed ping to add a new item to the pings queue, the loop inside the Message method picks the new item up and issues an event, via Response.Write (confirmed using Debug.Print on the server). However, the browser doesn't trigger onmessage until I press ping a second time, and the browser issues another event; at which point the data from the first event reaches onmessage.
How can I fix this?
To clarify, this is the behavior I would expect:
Client Server
-------------------------------------------------------------------
Press Ping button
XHR to /home/ping
Eneque new item to pings
Message loop issues server-sent event
EventSource calls onmessage
This is what is actually happening:
Client Server
-------------------------------------------------------------------
Press Ping button
XHR to /home/ping
Eneque new item to pings
Message loop issues server-sent event
(Nothing happens)
Press Ping button again
New XHR to /home/ping
EventSource calls onmessage with previous event data
(While running in Chrome the message request is listed in the Network tab as always pending. I'm not sure if this is the normal behavior of server-sent events, or perhaps it's related to the issue.)
Edit
The string representation of the msg variable after Response.Write looks like this:
"data:{\"UserID\":105,\"Date\":\"2016-03-11T04:20:24.1854996+02:00\"}\n\n"
very clearly including the newlines.

This isn't an answer per say but hopefully it will lead one. I was able to get it working with the following code.
public void Ping(int id)
{
pings.Enqueue(new PingData { ID = id });
Response.ContentType = "text/plain";
Response.Write("id received");
}
public void Message()
{
int count = 0;
Response.ContentType = "text/event-stream";
do {
PingData nextPing;
if (pings.TryDequeue(out nextPing)) {
Response.ClearContent();
Response.Write("data:" + nextPing.ID.ToString() + " - " + nextPing.Date.ToLongTimeString() + "\n\n");
Response.Write("event:time" + "\n" + "data:" + DateTime.Now.ToLongTimeString() + "\n\n");
count = 0;
Response.Flush();
}
if (!Response.IsClientConnected){break;}
Thread.Sleep(1000);
count++;
} while (count < 30); //end after 30 seconds of no pings
}
The line of code that makes the difference is the second Response.Write. The message doesn't appear in the browser until the next ping similar to your issue, but the ping always appears. Without that line the ping will appear only after the next ping, or once my 30 second counter runs out.
The missing message appearing after the 30 second timer leads me to conclude that this is either a .Net issue, or there's something we're missing. It doesn't seem to be an event source issue because the message appears on a server event, and I've had no trouble doing SSE with PHP.
For reference, here's the JavaScript and HTML I used to test with.
<input type="text" id="pingid" placeholder="ID" /><br />
<input type="button" id="ping" value="Ping" />
<div id="timeresponse"></div>
<div id="pingresponse"></div>
<script>
var es = new EventSource('/Home/Message');
es.onmessage = function (e) {
console.log(e.data);
document.getElementById('pingresponse').innerHTML += e.data + " - onmessage<br/>";
};
es.addEventListener("ping", function (e) {
console.log(e.data);
document.getElementById('pingresponse').innerHTML += e.data + " - onping<br/>";
}, false);
es.addEventListener("time", function (e) {
document.getElementById('timeresponse').innerHTML = e.data;
}, false);
es.onerror = function () {
console.log(arguments);
console.log("event source closed");
es.close();
};
window.onload = function(){
document.getElementById('ping').onclick = function () {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onload = function () {
console.log(this.responseText);
};
var url = '/Home/Ping?id=' + document.getElementById('pingid').value;
xmlhttp.open("GET", url);
xmlhttp.send();
};
};
</script>

Since an eventstream is just text data, missing the double line break before the first event is written to response could affect the client. The example from mdn docs suggests
header("Content-Type: text/event-stream\n\n");
Which could be applied apply to .NET response handling (note the side effects of Response.ClearContent()).
If it feels too hacky, you could start your stream with a keep-alive comment (if you want to avoid timing out you may have to send comments periodically):
: just a keep-alive comment followed by two line-breaks, Response.Write me first

I'm not sure if this will work because I can't try it now, but what about to add an End?:
Response.Flush();
Response.End();

The default behavior of .net is to serialize access to session state. It blocks parallel execution. Requests are processed sequentially and access to session state is exclusive for the session. You can override the default state per class.
[SessionState(SessionStateBehavior.Disabled)]
public class MyPulsingController
{
}
There is an illustration of this in the question here.

EDIT: Would you please try creating the object first and then passing it to Enqueue? As in:
PingData myData = new PingData { UserID = userID };
pings.Enqueue(myData);
There might be something strange going on where Dequeue thinks it's done the job but the the PingData object isn't properly constructed yet.
Also can we try console.log("I made it to the function") instead of console.log(e.data).
---- PREVIOUS INFORMATION REQUESTED BELOW ----
Please make sure that the server Debug.Print confirms this line of code:
Response.Write("data:" + JsonConvert.SerializeObject(nextPing, Formatting.None) + "\n\n");
Is actually executed? Please double check this. If you can capture the server sent response then can we see what it is?
Also could we see what browsers you've tested on? Not all browsers support server events.

Related

MVC SignalR keep increasing request count on each reload

I'm creating an ASP.NET MVC application which uses "SqlDependecy" and "SignalR" technologies to maintain real-time communication with the server based on database changes. It simply inspect a field value changes in specific database record and then display it on the browser.
The attempt works perfectly fine. But when I monitor the network requests through the browsers "Network" performance, the request count increases by 1 in every refresh of the page.
As in the image.
Initial page load only make one request.
First refresh after the initial load and then db change will lead to make 2 requests.
Second refresh after the initial load and then db change will lead to make 3 requests.
so on...
The js code I tried is given below.
It seams as an problem to me. If this is a real problem, Any advice on this will be highly appreciated. Thank you very much.
<script type="text/javascript">
$(function () {
var jHub = $.connection.journeyHub;
$.connection.hub.start();
jHub.client.ListenChange = function () {
getData();
}
jHub.client.ListenChange();
});
function getData() {
$.ajax({
url: 'GetValue',
type: 'GET',
dataType: 'json',
success: function (data) {
if (data == "pending") {
$("#box").css({ "background-color": "orange" });
}
else if (data == "deny") {
$("#box").css({ "background-color": "red" });
}
else if (data == "success") {
$("#box").css({ "background-color": "green" });
}
}
});
}
</script>
<div id="box" style="width:100px; height:100px; background-color: gray;"></div>
[Edit v1]
Here is my Controller where the event handler is located.
public class TravelController : Controller
{
SqlConnection link = new SqlConnection(ConfigurationManager.ConnectionStrings["linkTraveller"].ConnectionString);
// GET: Travel
public ActionResult Listen()
{
return View();
}
public ActionResult GetValue()
{
using (IDbConnection conn = link)
{
string query = #"SELECT [Status] FROM [dbo].[Journey] WHERE [Id]=1";
SqlCommand command = new SqlCommand(query, link);
SqlDependency sqlDep = new SqlDependency(command);
sqlDep.OnChange += new OnChangeEventHandler((sender, e) => sqlDep_OnChange(sender, e));
conn.Open();
string status = command.ExecuteScalar().ToString();
return Json(status, JsonRequestBehavior.AllowGet);
}
}
private void sqlDep_OnChange(object sender, SqlNotificationEventArgs e)
{
JourneyHub.Start();
}
}
Here is the Hub
public class JourneyHub : Hub
{
public static void Start()
{
var context = GlobalHost.ConnectionManager.GetHubContext<JourneyHub>();
context.Clients.All.ListenChange();
}
}
Off the top of my head, I would say you are not decrementing your trigger handlers, sql dependency triggers only fire once and then they are gone, you have to remember the remove the event handler for it or they just keep adding but, but I will know for sure if you can post your sql dependency trigger code.
Here is a sample from something I did many years ago, but the idea is still the same.
try
{
using (
var connection =
new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand(#"SELECT [Id]
,[FName]
,[LName]
,[DOB]
,[Notes]
,[PendingReview]
FROM [dbo].[Users]",
connection))
{
// Make sure the command object does not already have
// a notification object associated with it.
command.Notification = null;
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
command.ExecuteReader();
}
}
}
catch (Exception e)
{
throw;
}
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
SqlDependency dependency = sender as SqlDependency;
if (dependency != null) dependency.OnChange -= dependency_OnChange;
//Recall your SQLDependency setup method here.
SetupDependency();
JobHub.Show();
}

Call SignalR Javascript function from modal popup

My DiaryHub.vb has the following:
Imports Microsoft.AspNet.SignalR
Imports Microsoft.AspNet.SignalR.Hubs
Namespace UIS
<HubName("DiaryHub")>
Public Class DiaryHub
Inherits Hub
Public Sub PostDiaryHeadline()
' Call the addNewMessageToPage method to update clients.
Clients.All.addNewDiaryHeadlineToPage()
End Sub
End Class
End Namespace
My Home/Index window has the following code to initiate/configure SignalR.
$(function () {
// Save the reference to the SignalR hub
var dHub = $.connection.DiaryHub;
// Invoke the function to be called back from the server
// when changes are detected
// Create a function that the hub can call back to display new diary Headline entry.
dHub.client.addNewDiaryHeadlineToPage = function () {
// refresh the Headline Entries to the page.
outputHLDiaryEntries();
};
// Start the SignalR client-side listener
$.connection.hub.start().done(function () {
// Do here any initialization work you may need
outputHLDiaryEntries();
});
})
The code works and on launch the Headline diary entries are displayed.
I also have a button that opens a Kendo window as a modal with a form for adding new diary entries using this function:
function openAddWindow() {
var addWindow = $("#window").data("kendoWindow");
addWindow.refresh({
url: "Home/AddDiaryEntry/"
});
addWindow.open();
addWindow.center();
}
I then have the following Javascript in my AddDiaryEntry page:
function createDiaryEntry() {
var validFlag = true;
var errorMsg = "";
//Validate New Diary Entry
// removed for brevity...
if (validFlag) {
//data is valid
//get value of checkbox
var cbValue = ($("#addNew_dHeadline").is(':checked')) ? true : false;
//clear error area
$('#errorArea').html("");
var response = ''
$.ajax({
url: 'Home/SaveDiaryEntry',
type: 'POST',
data: {
dDate: $("#addNew_dDate").text(),
dCreatedBy: $("#addNew_dCreatedBy").text(),
dName: '#AppShort',
dTeam: teamValue.value(),
dType: typeValue.value(),
dRef: $("#addNew_dREF").val(),
dHeadline: cbValue,
dServer: multiSelect.value(),
dComment: editor.value()
},
success: function (result) {
response = result;
alert(response);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
response = "err--" + XMLHttpRequest.status + " -- " + XMLHttpRequest.statusText + " -- " + errorThrown;
alert(response);
}
});
//close window
var addWindow = $("#window").data("kendoWindow");
addWindow.close();
//if headline entry call SignalR post function to refresh diary entries
if (cbValue) {
// reference to the SignalR hub
var dHub = $.connection.DiaryHub;
// function to update all clients
dHub.client.PostDiaryHeadline(); //THIS IS A FUNCTION IN DiaryHub.vb
}
} else {
//error in data
var out = '<ul class="error">' + errorMsg + '</ul>';
// display errors
$('#errorArea').html(out);
}
}
The code works fine - validates the data, saves data to database. The issue I'm having is when I try to call dHub.client.PostDiaryHeadline() to invoke the SignalR function. I get the error: JavaScript runtime error: Object doesn't support property or method 'PostDiaryHeadline'
How do I call the function? Should I call the function before I close the modal window?
From what I can see your actually expecting a response rather than a server call.
adding server will fire a request.
if (cbValue) {
// reference to the SignalR hub
var dHub = $.connection.DiaryHub;
// function to update all clients
dHub.server.PostDiaryHeadline(); //THIS IS A FUNCTION IN DiaryHub.vb
}
Your already receiving the response here:
dHub.client.addNewDiaryHeadlineToPage = function () {
// refresh the Headline Entries to the page.
outputHLDiaryEntries();
};
//EDIT
There seems to be slight issues through out, so apart from the above(which needs fixing).
On the hub name (backend) replace with: <HubName("diaryHub")>
In your JS replace with: var dHub = $.connection.diaryHub;
Finally in your createDiaryEntry(); body should look like so:
$.connection.hub.start().done(function () {
// Do here any initialization work you may need
if (cbValue) {
// reference to the SignalR hub
var dHub = $.connection.diaryHub;
// function to update all clients
dHub.server.postDiaryHeadline(); //THIS IS A FUNCTION IN DiaryHub.vb
}
});
There are a few SignalR issues but that should get you on the right path.
Most SignalR issues stem from case sensitivity and structuring. All very common.
Should be the last issue, replace with: dHub.server.postDiaryHeadline();
lower case "p"

Call MVC action method by javascript but not using AJAX

I have a MVC3 action method with 3 parameters like this:
var url = "/Question/Insert?" + "_strTitle='" + title + "'&_strContent='" + content + "'&_listTags='" + listTags.toString() + "'";
and I want to call this by normal javascript function not AJAX (because it's not necessary to use AJAX function)
I tried to use this function but it didn't work:
window.location.assign(url);
It didn't jump to Insert action of QuestionController.
Is there someone would like to help me? Thanks a lot
This is more detail
I want to insert new Question to database, but I must get data from CKeditor, so I have to use this function below to get and validate data
// insert new question
$("#btnDangCauHoi").click(function () {
//validate input data
//chủ đề câu hỏi
var title = $("#txtTitle").val();
if (title == "") {
alert("bạn chưa nhập chủ đề câu hỏi");
return;
}
//nội dung câu hỏi
var content = GetContents();
content = "xyz";
if (content == "") {
alert("bạn chưa nhập nội dung câu hỏi");
return;
}
//danh sách Tag
var listTags = new Array();
var Tags = $("#list_tag").children();
if (Tags.length == 0) {
alert("bạn chưa chọn tag cho câu hỏi");
return;
}
for (var i = 0; i < Tags.length; i++) {
var id = Tags[i].id;
listTags[i] = id;
//var e = listTags[i];
}
var data = {
"_strTitle": title,
"_strContent": content,
"_listTags": listTags.toString()
};
// $.post(url, data, function (result) {
// alert(result);
// });
var url = "/Question/Insert?" + "_strTitle='" + title + "'&_strContent='" + content + "'&_listTags='" + listTags.toString() + "'";
window.location.assign(url); // I try to use this, and window.location also but they're not working
});
This URL call MVC action "Insert" below by POST method
[HttpPost]
[ValidateInput(false)]
public ActionResult Insert(string _strTitle, string _strContent, string _listTags)
{
try
{
//some code here
}
catch(Exception ex)
{
//if some error come up
ViewBag.Message = ex.Message;
return View("Error");
}
// if insert new question success
return RedirectToAction("Index","Question");
}
If insert action success, it will redirect to index page where listing all question include new question is already inserted. If not, it will show error page. So, that's reason I don't use AJAX
Is there some one help me? Thanks :)
Try:
window.location = yourUrl;
Also, try and use Fiddler or some other similar tool to see whether the redirection takes place.
EDIT:
You action is expecting an HTTP POST method, but using window.location will cause GET method. That is the reason why your action is never called.
[HttpPost]
[ValidateInput(false)]
public ActionResult Insert(string _strTitle, string _strContent, string _listTags)
{
// Your code
}
Either change to HttpGet (which you should not) or use jQuery or other library that support Ajax in order to perform POST. You should not use GET method to update data. It will cause so many security problems for your that you would not know where to start with when tackling the problem.
Considering that you are already using jQuery, you might as well go all the way and use Ajax. Use $.post() method to perform HTTP POST operation.
Inside a callback function of the $.post() you can return false at the end in order to prevent redirection to Error or Index views.
$.post("your_url", function() {
// Do something
return false; // prevents redirection
});
That's about it.
You could try changing
var url = "/Question/Insert?" + "_strTitle='" + title + "'&_strContent='" + content + "'&_listTags='" + listTags.toString() + "'";
to
var url = "/Question/Insert?_strTitle=" + title + "&_strContent=" + content + "&_listTags=" + listTags.toString();
I've removed the single quotes as they're not required.
Without seeing your php code though it's not easy to work out where the problem is.
When you say "It didn't jump to Insert action of QuestionController." do you mean that the browser didn't load that page or that when the url was loaded it didn't route to the expected controller/action?
You could use an iframe if you want to avoid using AJAX, but I would recommend using AJAX
<iframe src="" id="loader"></iframe>
<script>
document.getElementById("loader").src = url;
</script>

Uploadify response value is always undefined from ASP.NET

I'm using Uploadify to upload some images with ASP.NET.
I use Response.WriteFile() in ASP.NET to return the result of the upload back to JavaScript.
As specified in the documentation I'm using onAllComplete event to check for response string from ASP.NET.
The problem is it that the alert(response); is always undefined in JavaScript.
JavaScript code as below:
$(document).ready(function() {
var auth = "<% = Request.Cookies[FormsAuthentication.FormsCookieName]==null ? string.Empty : Request.Cookies[FormsAuthentication.FormsCookieName].Value %>";
$('#btnUpdateProfileImg').uploadify({
'uploader': '../script/uploadify/uploadify.swf',
'script': '../uploadprofimg.aspx',
'cancelImg': '../script/uploadify/cancel.png',
'folder': '../script/uploadify',
'scriptData': { 'id': $(this).attr("id"), 'token': auth },
'onAllComplete': function(event, queueID, fileObj, response, data) {
alert(response);
}
});
});
ASP.NET code a below;
protected void Page_Load(object sender, EventArgs e)
{
try
{
string token = Request.Form["token"].ToString();
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(token);
if (ticket != null)
{
var identity = new FormsIdentity(ticket);
if (identity.IsAuthenticated)
{
HttpPostedFile hpFile = Request.Files["ProfileImage"];
string appPath = HttpContext.Current.Request.ApplicationPath;
string fullPath = HttpContext.Current.Request.MapPath(appPath) + #"\avatar\";
hpFile.SaveAs(Server.MapPath("~/" + uniqName));
Response.ContentType = "text/plain";
Response.Write("test");
}
}
}
catch (Exception ex)
{
Response.Write("test");
}
}
Reason for the FormsAuthenticationTicket object is to pass the authentication cookie though when using the Uploadify with Firefox.
I have seen many examples where Response.Write returns a value back to the onAllComplete event. But all I get is undefined.
I have also tried to use Context.Response.Write, this.Response.Write, HttpContext.Current.Response.Write. They all return undefined.
Any help appreciated.
Thanks
It seems that the onAllComplete event never fires. This is possibly because I'm automatically uploading single files rather than multiple files.
I find that the onComplete event fires and I can use that instead.

Is it possible to ping a server from Javascript?

I'm making a web app that requires that I check to see if remote servers are online or not. When I run it from the command line, my page load goes up to a full 60s (for 8 entries, it will scale linearly with more).
I decided to go the route of pinging on the user's end. This way, I can load the page and just have them wait for the "server is online" data while browsing my content.
If anyone has the answer to the above question, or if they know a solution to keep my page loads fast, I'd definitely appreciate it.
I have found someone that accomplishes this with a very clever usage of the native Image object.
From their source, this is the main function (it has dependences on other parts of the source but you get the idea).
function Pinger_ping(ip, callback) {
if(!this.inUse) {
this.inUse = true;
this.callback = callback
this.ip = ip;
var _that = this;
this.img = new Image();
this.img.onload = function() {_that.good();};
this.img.onerror = function() {_that.good();};
this.start = new Date().getTime();
this.img.src = "http://" + ip;
this.timer = setTimeout(function() { _that.bad();}, 1500);
}
}
This works on all types of servers that I've tested (web servers, ftp servers, and game servers). It also works with ports. If anyone encounters a use case that fails, please post in the comments and I will update my answer.
Update: Previous link has been removed. If anyone finds or implements the above, please comment and I'll add it into the answer.
Update 2: #trante was nice enough to provide a jsFiddle.
http://jsfiddle.net/GSSCD/203/
Update 3: #Jonathon created a GitHub repo with the implementation.
https://github.com/jdfreder/pingjs
Update 4: It looks as if this implementation is no longer reliable. People are also reporting that Chrome no longer supports it all, throwing a net::ERR_NAME_NOT_RESOLVED error. If someone can verify an alternate solution I will put that as the accepted answer.
Ping is ICMP, but if there is any open TCP port on the remote server it could be achieved like this:
function ping(host, port, pong) {
var started = new Date().getTime();
var http = new XMLHttpRequest();
http.open("GET", "http://" + host + ":" + port, /*async*/true);
http.onreadystatechange = function() {
if (http.readyState == 4) {
var ended = new Date().getTime();
var milliseconds = ended - started;
if (pong != null) {
pong(milliseconds);
}
}
};
try {
http.send(null);
} catch(exception) {
// this is expected
}
}
you can try this:
put ping.html on the server with or without any content, on the javascript do same as below:
<script>
function ping(){
$.ajax({
url: 'ping.html',
success: function(result){
alert('reply');
},
error: function(result){
alert('timeout/error');
}
});
}
</script>
You can't directly "ping" in javascript.
There may be a few other ways:
Ajax
Using a java applet with isReachable
Writing a serverside script which pings and using AJAX to communicate to your serversidescript
You might also be able to ping in flash (actionscript)
You can't do regular ping in browser Javascript, but you can find out if remote server is alive by for example loading an image from the remote server. If loading fails -> server down.
You can even calculate the loading time by using onload-event. Here's an example how to use onload event.
Pitching in with a websocket solution...
function ping(ip, isUp, isDown) {
var ws = new WebSocket("ws://" + ip);
ws.onerror = function(e){
isUp();
ws = null;
};
setTimeout(function() {
if(ws != null) {
ws.close();
ws = null;
isDown();
}
},2000);
}
Update: this solution does not work anymore on major browsers, since the onerror callback is executed even if the host is a non-existent IP address.
To keep your requests fast, cache the server side results of the ping and update the ping file or database every couple of minutes(or however accurate you want it to be). You can use cron to run a shell command with your 8 pings and write the output into a file, the webserver will include this file into your view.
The problem with standard pings is they're ICMP, which a lot of places don't let through for security and traffic reasons. That might explain the failure.
Ruby prior to 1.9 had a TCP-based ping.rb, which will run with Ruby 1.9+. All you have to do is copy it from the 1.8.7 installation to somewhere else. I just confirmed that it would run by pinging my home router.
There are many crazy answers here and especially about CORS -
You could do an http HEAD request (like GET but without payload).
See https://ochronus.com/http-head-request-good-uses/
It does NOT need a preflight check, the confusion is because of an old version of the specification, see
Why does a cross-origin HEAD request need a preflight check?
So you could use the answer above which is using the jQuery library (didn't say it) but with
type: 'HEAD'
--->
<script>
function ping(){
$.ajax({
url: 'ping.html',
type: 'HEAD',
success: function(result){
alert('reply');
},
error: function(result){
alert('timeout/error');
}
});
}
</script>
Off course you can also use vanilla js or dojo or whatever ...
If what you are trying to see is whether the server "exists", you can use the following:
function isValidURL(url) {
var encodedURL = encodeURIComponent(url);
var isValid = false;
$.ajax({
url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" + encodedURL + "%22&format=json",
type: "get",
async: false,
dataType: "json",
success: function(data) {
isValid = data.query.results != null;
},
error: function(){
isValid = false;
}
});
return isValid;
}
This will return a true/false indication whether the server exists.
If you want response time, a slight modification will do:
function ping(url) {
var encodedURL = encodeURIComponent(url);
var startDate = new Date();
var endDate = null;
$.ajax({
url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" + encodedURL + "%22&format=json",
type: "get",
async: false,
dataType: "json",
success: function(data) {
if (data.query.results != null) {
endDate = new Date();
} else {
endDate = null;
}
},
error: function(){
endDate = null;
}
});
if (endDate == null) {
throw "Not responsive...";
}
return endDate.getTime() - startDate.getTime();
}
The usage is then trivial:
var isValid = isValidURL("http://example.com");
alert(isValid ? "Valid URL!!!" : "Damn...");
Or:
var responseInMillis = ping("example.com");
alert(responseInMillis);
const ping = (url, timeout = 6000) => {
return new Promise((resolve, reject) => {
const urlRule = new RegExp('(https?|ftp|file)://[-A-Za-z0-9+&##/%?=~_|!:,.;]+[-A-Za-z0-9+&##/%=~_|]');
if (!urlRule.test(url)) reject('invalid url');
try {
fetch(url)
.then(() => resolve(true))
.catch(() => resolve(false));
setTimeout(() => {
resolve(false);
}, timeout);
} catch (e) {
reject(e);
}
});
};
use like this:
ping('https://stackoverflow.com/')
.then(res=>console.log(res))
.catch(e=>console.log(e))
I don't know what version of Ruby you're running, but have you tried implementing ping for ruby instead of javascript? http://raa.ruby-lang.org/project/net-ping/
let webSite = 'https://google.com/'
https.get(webSite, function (res) {
// If you get here, you have a response.
// If you want, you can check the status code here to verify that it's `200` or some other `2xx`.
console.log(webSite + ' ' + res.statusCode)
}).on('error', function(e) {
// Here, an error occurred. Check `e` for the error.
console.log(e.code)
});;
if you run this with node it would console log 200 as long as google is not down.
You can run the DOS ping.exe command from javaScript using the folowing:
function ping(ip)
{
var input = "";
var WshShell = new ActiveXObject("WScript.Shell");
var oExec = WshShell.Exec("c:/windows/system32/ping.exe " + ip);
while (!oExec.StdOut.AtEndOfStream)
{
input += oExec.StdOut.ReadLine() + "<br />";
}
return input;
}
Is this what was asked for, or am i missing something?
just replace
file_get_contents
with
$ip = $_SERVER['xxx.xxx.xxx.xxx'];
exec("ping -n 4 $ip 2>&1", $output, $retval);
if ($retval != 0) {
echo "no!";
}
else{
echo "yes!";
}
It might be a lot easier than all that. If you want your page to load then check on the availability or content of some foreign page to trigger other web page activity, you could do it using only javascript and php like this.
yourpage.php
<?php
if (isset($_GET['urlget'])){
if ($_GET['urlget']!=''){
$foreignpage= file_get_contents('http://www.foreignpage.html');
// you could also use curl for more fancy internet queries or if http wrappers aren't active in your php.ini
// parse $foreignpage for data that indicates your page should proceed
echo $foreignpage; // or a portion of it as you parsed
exit(); // this is very important otherwise you'll get the contents of your own page returned back to you on each call
}
}
?>
<html>
mypage html content
...
<script>
var stopmelater= setInterval("getforeignurl('?urlget=doesntmatter')", 2000);
function getforeignurl(url){
var handle= browserspec();
handle.open('GET', url, false);
handle.send();
var returnedPageContents= handle.responseText;
// parse page contents for what your looking and trigger javascript events accordingly.
// use handle.open('GET', url, true) to allow javascript to continue executing. must provide a callback function to accept the page contents with handle.onreadystatechange()
}
function browserspec(){
if (window.XMLHttpRequest){
return new XMLHttpRequest();
}else{
return new ActiveXObject("Microsoft.XMLHTTP");
}
}
</script>
That should do it.
The triggered javascript should include clearInterval(stopmelater)
Let me know if that works for you
Jerry
You could try using PHP in your web page...something like this:
<html><body>
<form method="post" name="pingform" action="<?php echo $_SERVER['PHP_SELF']; ?>">
<h1>Host to ping:</h1>
<input type="text" name="tgt_host" value='<?php echo $_POST['tgt_host']; ?>'><br>
<input type="submit" name="submit" value="Submit" >
</form></body>
</html>
<?php
$tgt_host = $_POST['tgt_host'];
$output = shell_exec('ping -c 10 '. $tgt_host.');
echo "<html><body style=\"background-color:#0080c0\">
<script type=\"text/javascript\" language=\"javascript\">alert(\"Ping Results: " . $output . ".\");</script>
</body></html>";
?>
This is not tested so it may have typos etc...but I am confident it would work. Could be improved too...

Categories

Resources