We have a website that can be viwed from a kiosk in a shop.
When the inactivity is above 2 minutes, the site returns to the home.
Anyone knows how to refresh the session when this appens?
It could also serve make a refresh of the user id, but I don't know how it works.
I'm going to assume you are talking about Adobe Analytics javascript library and not the Android/iOS SDK, based on your tagging and lack of mention of it. If your kiosk is in fact using Android or iOS SDK, then please comment and I can update with instructions for that.
Adobe Analytics javascript library does not currently offer a direct method to force refresh an Adobe Analytics session/userID. However, you can effectively do it by explicitly setting s.visitorID yourself, which will override the default generated by the library.
So, when you want to start a new session, you can pop s.visitorID with for example the current timestamp:
s.visitorID = (new Date()).getTime().toString();
Or maybe you already have a "session" id you generate that you can use, instead.
Note: with this method, you must set s.visitorID (with the same value) for every hit for the duration of your session. So in practice, you would really do something more along the lines of generate the new value at start of session, put the value in a cookie, and put s.visitorID in s_doPlugin but it reads the cookie value.
Note: This will effectively make your visits and visitors metrics the same. Which is to be expected with a publicly shared device, but just mentioning it in case it comes up later.
pseudocode:
function startNewSession() {
// use whatever cookie writing utility you have to
// set a cookie named visitorID set to the generated
// value. In practice, the expiration doesn't really
// matter as long as it's something longer than
// your average session. Just setting it to default
// session expiration should be okay
var visitorID = (new Date()).getTime().toString();
setCookie('visitorID',visitorID);
}
// in your existing logic that times out returning
// home after 2 minutes of inactivity, call the function
// to generate a new id
startNewSession();
// this is AA's s_doPlugins callback function. This may look
// slightly different, maybe defined as s_doPlugins and then assigned
// to s.doPlugins, depending on what AA lib version you are using.
// This is AA's callback function that gets called whenever
// an s.t or s.tl call is made
s.usePlugins=true;
s.doPlugins=function(s) {
// make sure visitorID variable is addedto linkTrackVars
// so it gets 'registered' for s.tl calls.
s.linkTrackVars='visitorID';
// explicitly set the visitorID with the cookie, using
// whatever cookie reading utility you have.
s.visitorID=readCookie('visitorID');
}
Related
widgetPerformUpdateWithCompletionHandler() gives us the possibility to let the Notification Center know if the content of a Today Extension has changed. For example:
func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)!) {
// Refresh the widget's contents in preparation for a snapshot.
// Call the completion handler block after the widget's contents have been
// refreshed. Pass NCUpdateResultNoData to indicate that nothing has changed
// or NCUpdateResultNewData to indicate that there is new data since the
// last invocation of this method.
if(has_new_data()) { // There was an update
completionHandler(.NewData)
}
else { // nothing changed!
completionHandler(.NoData)
}
}
But how would we know if the content has changed? On every snapshot the widget is instantiated from scratch. It is a complete new process with new PID. So you can not store any property in your instance. How would one compare the current widget content with the content of the previous snapshot?
I used Core Data to store the current content for later comparison. This is obvious and works. But then another problem crashes in: What if there is no previous snapshot? Let's say the user removed the widget just to re-add it again. Or the user rebooted. There might be more reasons why there is no previous snapshot that I can not think of now. Either way - there still is content stored in Core Data. If the comparison between this old content and the current content detects there are no changes and I return .NoData the widget would end up empty because the Notification Center would not redraw the content.
You might wonder why It is so important to me to call the completionHandler with a correct state and not simply always return .NewData. That's because I am experiencing a little flicker when there is no change and still return .NewData. I have some images in my widget and when redrawing the widget the whole content gets invisible for a millisecond - long enough to notice.
Is there something I am missing? It seems strange to me that Apple provides a way to give us the option to respond with different states but then makes it impossible to detect which state we should respond.
In theory you would use this to check whether there was any new content since the last call, and pass back the appropriate value. I suppose in theory it might be the same instance of the view controller on more than one call, but that's clearly not how things work right now. Checking whether content has changed depends on the nature of the app and the extension. Since you're using a shared Core Data store to share data, you might do something like:
Any time the app changes data, save the current date in shared user defaults.
Any time the today extension reads data, save the current date in shared user defaults.
When widgetPerformUpdateWithCompletionHandler is called, look up both of those dates. If the data has changed more recently than the last time the extension read that data, return NCUpdateResultNewData. If not, return NCUpdateResultNoData.
You could also save these dates in the metadata on the persistent store instead of in shared user defaults. If it was the same view controller each time, you might keep the value from step 2 in memory instead of saving it to a file. But again that's not how it works now, and it's not clear when or if that will change.
Apps that save data in some other way might need to use different checks, the details of which would depend on how their app and extension worked.
In practice with iOS 8.2 it really doesn't matter because the extension environment doesn't seem to care what value you send back. I tried returning NCUpdateResultNewData and compared it to returning NCUpdateResultNoData every time. There was absolutely no effect on the life cycle of the today extension view controller or its views.
As an aside, it's not always a different process. I tried putting this line in the today extension's viewDidLoad:
NSLog(#"viewDidLoad pid=%d self=%#", getpid(), self);
Then I ran the today extension, scrolled up and down in the notification center a couple of times, closed the notification center, reopened it, and got the following:
2015-03-17 15:19:01.203 DemoToday[3484:903442] viewDidLoad pid=3484 self=<TodayViewController: 0x12d508cc0>
2015-03-17 15:19:14.441 DemoToday[3484:903442] viewDidLoad pid=3484 self=<TodayViewController: 0x12d50ade0>
2015-03-17 15:19:23.784 DemoToday[3484:903442] viewDidLoad pid=3484 self=<TodayViewController: 0x12d619c40>
2015-03-17 15:19:29.015 DemoToday[3484:903442] viewDidLoad pid=3484 self=<TodayViewController: 0x12d50abe0>
Although it's a different instance of the view controller each time, it's the same pid in each of these cases.
You can use any storage API ( Core Data, NSCoding, SQLite ) as long as you enable data sharing with your host app.
https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html
Even if the user removes the widget or reboots the device, the data will be stored on your shared container. Whenever iOS launches your widget, you will be able to read and write the same shared container that you have previously used.
Be aware that your host app and your widget may read or write concurrently so you have to coordinate any reading and writing operation.
The simplest way to do this is to cache your current widgets state in user defaults. Then when the widget loads (in viewDidLoad) fetch your cached data from user defaults and set it as a property on your widget view controller.
Then when widgetPerformUpdateWithCompletionHandler is called you have your previous updated and you can decide if you need to do a network request of if your data is fresh enough. If you do a web request you can then compare it to your cache to determine if you have new data or no update.
No need to persist any data in UserDefaults or even Core Storage. Keep it simple: Just declare the variable(s) you use to store any calculated contents or data you use to check whether something changed to be static. Since the widget runs in the same process (as shown here) the static data will be available the next time your widget is activated.
static NSDate *lastDate;
- (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult))completionHandler {
NSDate * currentDate = [NSDate date];
if (!lastDate ||
[[NSCalendar currentCalendar]compareDate:lastDate toDate:currentDate toUnitGranularity:NSCalendarUnitDay] != NSOrderedSame) {
// Date changed
lastDate = currentDate;
... do whatever needs to be done ...
completionHandler(NCUpdateResultNewData);
} else {
completionHandler(NCUpdateResultNoData);
}
}
We just upgraded our Heroku postgres database using the follower changeover method. We have over 50 dataclips attached to the old database, and now we need to move them over to the new database. However, doing them one by one will take a lot of time.
Is there a programatic way to update the database a dataclip is attached to, perhaps with the CLI tools?
At least once the old database has been deprovisioned, you can now (as of March 2016) reattach them to another database:
Go to https://dataclips.heroku.com/clips/recoverable. It will display your old database and a set of 'orphaned' dataclips and you can choose to transfer them to another database (in my case the promoted follower from the changeover).
Note that this only affects the dataclips that you created, it does not affect the dataclips one of your team members created and that you only had access to. So they will have to go through this process as well.
Official devcenter article: https://devcenter.heroku.com/articles/dataclips#dataclip-recovery
Thanks to Heroku CSRF measures, programmatically updating data clips is much more difficult than you might expect. You'll need to suck it up and start clicking buttons by hand, or beg their support team to do it for you, which is just as difficult.
There is no official support for programmatically moving the dataclips. That being said, you can script it out against their HTTP API.
The base URL is https://dataclips.heroku.com/api/v1/. There are three relevant endpoints:
clips /clips
resources (databases) /heroku_resources
move clip /clips/:slug/move
Find the slug of the clip you want to move, find the resource id of the new database, and make a post to the move clip endpoint:
POST /api/v1/clips/fjhwieufysdufnjqqueyuiewsr/move
Content-Type: application/json
{"heroku_resource_id":"resource123456789#heroku.com"}
I had over 300 dataclips to move. I used the following technique to update them all (essentially reverse engineering the dataclips API).
Open Chrome with Web Developer tools, Network tab.
Log into Heroku Dataclips
Observe the network call which returns all the dataclips, in JSON (https://dataclips.heroku.com/api/v1/clips). Take this response and extract out all dataclip slugs.
Update the database for one dataclip. Observe the network call which does this (https://dataclips.heroku.com/api/v1/clips/:slug/move). Right click, Copy as cURL. This is the easiest way to get all the correct parameters, since the API uses cookies for authentication.
Write a script that loops through each dataclip slug, and shells out to curl. In Ruby, this looks like:
slugs = <paste ids here>.split("\n")
slugs.each do |slug|
command = %Q(curl -v 'https://dataclips.heroku.com/api/v1/clips/#{slug}/move' -H 'Cookie: ...' --data '{"heroku_resource_id":"resource1234567#heroku.com"}')
puts command
system(command)
end
You can contact Heroku support, and they will bulk transfer the dataclips to your new database for you.
Batch working on dataclips
I've finally found a solution to work on my Dataclips as a batch using the javascript console and some scraping technique. I needed it to retrieve every dataclips. But it guess It can be updated as such:
// Go to the dataclip listing (https://data.heroku.com/dataclips).
// Then execute this script in your console.
// Be careful, this will focus a new window every 4 seconds, preventing
// you from working 4 seconds times the number of dataclips you have.
// Retrieve urls and titles
let dataclips = Array.
from(document.querySelectorAll('.rt-td:first-child a')).
map(el => ({ url: el.href, title: el.innerText }))
/**
* Allows waiting for a given timeout before execution.
* #param {number} seconds
*/
const timeout = function(seconds) {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, seconds);
})
}
/**
* Here are all the changes you want to apply to every single
* dataclip.
* #param {object} window
*/
const applyChanges = function(window) {
}
// With a fast connection, 4 seconds is OK. Dial it down if you
// have errors.
const expectedLoadTime = 4000 // ms
// This is the main loop, windows are opened one by one to ensure focus and a
// correct loading time.
for (const dataclip of dataclips) {
// This opens another window from the script, having access to its DOM.
// See https://github.com/buonomo/kazoo for a funnier example usage!
// And don't be shy to star and share :D
const externWindow = window.open(dataclip.url)
// A hack to wait for loading, this could be improved for sure.
await timeout(expectedLoadTime)
applyChanges(externWindow)
externWindow.close()
}
You'd still have to implement applyChanges yourself which I conceed is a bit tedious and I don't have time to do it know (if one does, please share!). But at least it can be done on all of your dataclips in a single function.
For an example usage of this script, you can take a look at the gist I made to scrape every dataclips and related errors.
We have a ASP.Net application that has been given a 20 minute sliding expiry for the session (and cookie).
However, we have some AJAX that is polling the server for new information. The downside of this of course is that the session will continue indefinitely, as it is being kept alive by the polling calls causing the expiry time to be refreshed. Is there a way of preventing this - i.e. to only allow the session to be refreshed on non-ajax calls?
Turning off sliding expiry is not really an option as this is an application that business users will be using for most of their day between telephone calls.
Other Stackoverflow discussions on this talk about maintaining 2 separate application (one for authenticated calls, one for unauthenticated. I'm not sure this will be an option as all calls need to be authenticated.
Any ideas?
As this question is old I am assuming it has been resolved or a workaround implemented. However, I wanted to mention that instead of AJAX polling the server to perform an operation we have utilized SignalR which allows both the client to communicate with the server via JQuery and/or the server to notify the client.
Check it out: Learn About ASP.NET SignalR
add below code to your controller action that you are reference for polling.Convert this into an attribute so it can be used everywhere. This line will not extend session timeout
[HttpPost]
public ActionResult Run()
{
Response.Cookies.Remove(FormsAuthentication.FormsCookieName);
return Json("");
}
There is no way to stop the ajax from keeping the session and cookies alive!
However, there is a way to achieve what you want to do. That is if the process I will describe will be ok to you.
I think what you really want to achieve is first to refresh your page with ajax so that some processes will be active and running. Also to know when the user has stopped operating the program.
If that is what you want then there is a simple process to achieve this
You will have your ajax running for the things you want to run.
You will remove the session you want to check if user has stopped operation on the page and manage the session as a variable instead.
The variable can be a global variable or a class variable that will be set to initial value whenever the user clicks an element on the page.
(You will select the click event of an element and set the variable to initial value)
You will increment the variable every given time (say every time your ajax runs)
You will also have a function/method run to check the value of that variable if it is greater than the value you set as limit. This can run every time your ajax runs or every time you want it to run (timed event).
If the value of your variable is greater than the limit set it should invalidate or clear session/log user out.
This way if user stops operating (clicking elements) the system on any page that this is running will eventually log out the current user and stop running the program.
I have done this by creating a hidden page in an i-Frame. Then using JavaScript it posts back every 18 minutes to keep the session alive. This works really well.
This example is from a ASP.NET Forms project but could be tweaked for MVC.
Create a page called KeepSessionAlive page and add a meta refresh tag
meta id="MetaRefresh" http-equiv="refresh" content="21600;url=KeepSessionAlive.aspx"
In the code behind
protected string WindowStatusText = "";
protected void Page_Load(object sender, EventArgs e)
{
//string RefreshValue = Convert.ToString((Session.Timeout * 60) - 60);
string RefreshValue = Convert.ToString((Session.Timeout * 60) - 90);
// Refresh this page 60 seconds before session timeout, effectively resetting the session timeout counter.
MetaRefresh.Attributes["content"] = RefreshValue + ";url=KeepSessionAlive.aspx?q=" + DateTime.Now.Ticks;
WindowStatusText = "Last refresh " + DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString();
}
Add the hidden iFrame in a master page
iframe ID="KeepAliveFrame" src="KeepSessionAlive.aspx" frameBorder="0" width="0" height="0"
Download example
In the latest Meteor release (version 0.5.8), Session has been removed from the server-side code.
Previously I've used Session to store client-specific variables for the server; what is the replacement for this functionality?
Example case: User One opens a browser, User Two opens a browser. One calls a method on the server setting some token, the other calls a method on the server doing the same. I then need to access this when the client requests something. How do I differentiate between the two?
You'll want to save your tokens to a collection in the database.
You could use a Session on the server if you wanted to simply by copying the session package into your application's packages directory and changing its package.js to also load on the server. But a Session is an in-memory data structure, and so won't work if you have multiple server instances; and you wouldn't be able to restart the server without losing your user's tokens.
If you store your tokens in the database they'll persist across server restarts, and will work with a future version of Meteor which is able to scale an application by adding more server instances when needed.
If you need to expire your tokens (so that your collection doesn't grow without bound), you could add a "lastUsed" Date field to your token collection, and periodically remove tokens that haven't been used for longer than your chosen expiration period.
You can use each one's session id which is unique to the tab too. Not too sure how to get the current session id but it should be there somewhere (you can see it in Meteor.default_server.sessions, so there is still a way:
Client js
Meteor.call("test", Meteor.default_connection._lastSessionId, function(err,result) {
console.log(result);
});
Server side Js
Session = {
set : function(key, value, sessionid) {
console.log(Meteor.default_server.sessions[sessionid]);
if(!Meteor.default_server.sessions[sessionid].session_hash) Meteor.default_server.sessions[sessionid].session_hash = {};
Meteor.default_server.sessions[sessionid].session_hash.key = value;
},
get : function(key, sessionid) {
if(Meteor.default_server.sessions[sessionid].session_hash)
return Meteor.default_server.sessions[sessionid].session_hash.key;
},
equals: function(key, value, sessionid) {
return (this.get(key, sessionid) == value)
},
listAllSessionids: function() {
return _.pluck(Meteor.default_server.sessions, "id");
}
};
Meteor.methods({
test:function(sessionid) {
if(!Session.get("initial_load", sessionid)) Session.set("initial_load", new Date().getTime(), sessionid);
return Session.get("initial_load", sessionid);
}
});
I hook into Meteor.default_connection._sessions to store the values so that theres some type of garbage collection involved when the session isn't valid anymore (i.e the user has closed his tabs) to prevent memory being wasted. In livedata_server.js these old sessions get destroyed after 1 minute of no activity on the DDP wire (like the heartbeat).
Because the server can see everyone's session you can use the sessionid to access another user's session data. and listAllSessionids to give out an array of all the sessionids currently active.
Automatically set session like this.userId in a Method without using a param in a call
It looks like there is functionality for this this but its not fully hooked up. The session id would be stored in this.sessionData but its likely still unfinished. Its there to be called in method but theres nowhere that its being set yet (in livedata_connection.js & livedata_server.js)
I'm new to the Go language (Golang) and I'm writing a web-based application. I'd like to use session variables, like the kind in PHP (variables that are available from one page to the next and unique for a user session). Is there something like that in Go? If not, how would I go about implementing them myself? Or what alternatives methods are there?
You probably want to take a look at gorilla. It has session support as documented here.
Other than that or possibly one of the other web toolkits for go you would have to roll your own.
Possible solutions might be:
goroutine per user session to store session variables in memory.
store your variables in a session cookie.
use a database to store user session data.
I'll leave the implementation details of each of those to the reader.
Here's an alternative in case you just want session support without a complete web toolkit.
https://github.com/bpowers/seshcookie
Here's another alternative (disclosure: I'm the author):
https://github.com/icza/session
Quoting from its doc:
This package provides an easy-to-use, extensible and secure session implementation and management. Package documentation can be found and godoc.org:
https://godoc.org/github.com/icza/session
This is "just" an HTTP session implementation and management, you can use it as-is, or with any existing Go web toolkits and frameworks.
Overview
There are 3 key players in the package:
Session is the (HTTP) session interface. We can use it to store and retrieve constant and variable attributes from it.
Store is a session store interface which is responsible to store sessions and make them retrievable by their IDs at the server side.
Manager is a session manager interface which is responsible to acquire a Session from an (incoming) HTTP request, and to add a Session to an HTTP response to let the client know about the session. A Manager has a backing Store which is responsible to manage Session values at server side.
Players of this package are represented by interfaces, and various implementations are provided for all these players.
You are not bound by the provided implementations, feel free to provide your own implementations for any of the players.
Usage
Usage can't be simpler than this. To get the current session associated with the http.Request:
sess := session.Get(r)
if sess == nil {
// No session (yet)
} else {
// We have a session, use it
}
To create a new session (e.g. on a successful login) and add it to an http.ResponseWriter (to let the client know about the session):
sess := session.NewSession()
session.Add(sess, w)
Let's see a more advanced session creation: let's provide a constant attribute (for the lifetime of the session) and an initial, variable attribute:
sess := session.NewSessionOptions(&session.SessOptions{
CAttrs: map[string]interface{}{"UserName": userName},
Attrs: map[string]interface{}{"Count": 1},
})
And to access these attributes and change value of "Count":
userName := sess.CAttr("UserName")
count := sess.Attr("Count").(int) // Type assertion, you might wanna check if it succeeds
sess.SetAttr("Count", count+1) // Increment count
(Of course variable attributes can be added later on too with Session.SetAttr(), not just at session creation.)
To remove a session (e.g. on logout):
session.Remove(sess, w)
Check out the session demo application which shows all these in action.
Google App Engine support
The package provides support for Google App Engine (GAE) platform.
The documentation doesn't include it (due to the +build appengine build constraint), but here it is: gae_memcache_store.go
The implementation stores sessions in the Memcache and also saves sessions to the Datastore as a backup in case data would be removed from the Memcache. This behaviour is optional, Datastore can be disabled completely. You can also choose whether saving to Datastore happens synchronously (in the same goroutine) or asynchronously (in another goroutine), resulting in faster response times.
We can use NewMemcacheStore() and NewMemcacheStoreOptions() functions to create a session Store implementation which stores sessions in GAE's Memcache. Important to note that since accessing the Memcache relies on Appengine Context which is bound to an http.Request, the returned Store can only be used for the lifetime of a request! Note that the Store will automatically "flush" sessions accessed from it when the Store is closed, so it is very important to close the Store at the end of your request; this is usually done by closing the session manager to which you passed the store (preferably with the defer statement).
So in each request handling we have to create a new session manager using a new Store, and we can use the session manager to do session-related tasks, something like this:
ctx := appengine.NewContext(r)
sessmgr := session.NewCookieManager(session.NewMemcacheStore(ctx))
defer sessmgr.Close() // This will ensure changes made to the session are auto-saved
// in Memcache (and optionally in the Datastore).
sess := sessmgr.Get(r) // Get current session
if sess != nil {
// Session exists, do something with it.
ctx.Infof("Count: %v", sess.Attr("Count"))
} else {
// No session yet, let's create one and add it:
sess = session.NewSession()
sess.SetAttr("Count", 1)
sessmgr.Add(sess, w)
}
Expired sessions are not automatically removed from the Datastore. To remove expired sessions, the package provides a PurgeExpiredSessFromDSFunc() function which returns an http.HandlerFunc. It is recommended to register the returned handler function to a path which then can be defined as a cron job to be called periodically, e.g. in every 30 minutes or so (your choice). As cron handlers may run up to 10 minutes, the returned handler will stop at 8 minutes
to complete safely even if there are more expired, undeleted sessions. It can be registered like this:
http.HandleFunc("/demo/purge", session.PurgeExpiredSessFromDSFunc(""))
Check out the GAE session demo application which shows how it can be used.
cron.yaml file of the demo shows how a cron job can be defined to purge expired sessions.
Check out the GAE session demo application which shows how to use this in action.