Closed JohnSundarraj closed 11 years ago
A lot has changed in Gate One 1.2 in regards to plugins and I haven't finished updating the documentation yet. If you tell me what you're trying to do or paste a code example I can show you how to make it work.
Also, there's two kinds of plugins now: Global (applies to all of Gate One) and application-specific (e.g. terminal plugins). These work slightly different from each other.
Dan, I'm using GateOne API auth mechanism. Whenever a user connects to GateOne, a session file has been created under that user directory( Hope i'm wright here). I'm trying to get GateOne session data in my PHP app, so that i can maintain a session table in my own database. Also i want to kill the session from my app itself via javascript websocket.
How can this be done, via plugin??. I read your ssh plugin's code, and i have already written some python code in my career. But cant understand the workflow of websockets in both javascript and python side in GateOne.
Finally i followed your ssh plugin and wrote some code, but no luck. Anyway i'm trying to write plugin for altering terminal app functionality.
Need guidance on developing plugin. Thanks for your reply.
Dan,
After debugging for sometime i found out the problem. Now i can execute my python plugin code via javascript websocket. I tested my plugin on chrome javascript console, by simply alerting a text string, it worked well. But When i executed my plugin function after GateOne.init({autoconnectUrl......})
in my php app, it throwed error GateOne.Myplugin.Test() function is undefined
. But executing the same function in console works. Need help on this.
To write a functionality on my plugin, i need a bit more knowledge on consuming your GateOne API. Anyway i need guidance on solving the above mentioned issue. Thanks in advance. Good job.
Well, plugins don't get downloaded/initialized until after GateOne.init() is called. So if you're calling one of your plugin's functions inside of GateOne.init() that won't work. What I usually do in those situations is set a pref at the top of my plugin like this:
if (!GateOne.prefs.playbackFrames) {
GateOne.prefs.playbackFrames = 75; // This is the default value
}
Then I can reference that setting in my plugin's init() function:
GateOne.Myplugin.init = function() { GateOne.prefs.playbackFrames; /* do stuff with it */}
This allows that preference to be overridden at runtime by GateOne.init() and also provide a default.
Having said all that, your problem might be simpler: Are you aware that your plugin's init() function will be called immediately after GateOne.init()? It's part of the initialization process.
You can also add a postInit() function to your plugin if you want something to be called after all the other init() functions but before Gate One is actually ready for use (it all happens in a second or so).
There's other mechanisms at your disposal to fire your plugin's functions when certain events occur. For example, if you want your plugin's function to be called whenever a new terminal is opened...
GateOne.Events.on('terminal:new_terminal', GateOne.Myplugin.someFunc);
That would call someFunc() whenever a new terminal is opened (the terminal number will be passed as an argument to someFunc). You can put that line of code in your plugin's init() function to have it automatically applied whenever Gate One is loaded. There's LOADS of events like that. You can even add your own. For example:
GateOne.Myplugin.myFunction: function() { console.log("I just ran myFunction!"); GateOne.Events.trigger("myplugin:my_function"); };
Then you can attach events to "myplugin:my_function" via the GateOne.Events.on() function and they'll get called automatically whenever myFunction() is called.
Hopefully that clarifies things a bit?
Just an FYI: You can email me your code (or a link to a private paste where I can view it) and I can take a look.
Here's my plugin code. myplugin.js
/**
* @file
* Plugin's main js file.
*/
(function(window,undefined) {
var document = window.document;
// Changing naming conventions.
var go = GateOne,
prefix = go.prefs.prefix,
u = go.Utils,
v = go.Visual,
E = go.Events,
t = go.Terminal,
urlObj = (window.URL || window.webkitURL),
logFatal = GateOne.Logging.logFatal,
logError = GateOne.Logging.logError,
logWarning = GateOne.Logging.logWarning,
logInfo = GateOne.Logging.logInfo,
logDebug = GateOne.Logging.logDebug;
// GateOne.MyPlugin object.
go.Base.module(GateOne,'MyPlugin','1.0',['Base','Net']);
// Internal properties of GateOne.MyPlugin object.
go.Base.update(go.MyPlugin,{
// Initializer.
init: function() {
go.Myplugin.settings = {};
go.MyPlugin.settings['url'] = null;
// Adding websocket actions.
go.Net.addAction('terminal:mypluginjs_sync_session',go.MyPlugin.syncSession);
},
getSession: function() {
// Sending hook's via websocket.
go.ws.send(JSON.stringify({'terminal:myplugin_get_session':true}));
},
syncSession: function(data) {
// My stuff goes here.
alert(JSON.stringify(data));
alert(go.MyPlugin.settings['url']); // This always says 'null', but i'm updating this in my php app.
}
});
})(window);
myplugin.py
# Importing python modules.
import os,logging,re
from utils import get_translation
# Get Translation.
_ = get_translation()
# Path to our plugin directory.
PLUGIN_PATH = os.path.split(__file__)[0]
# Get session data of current user.
def get_session(self,data):
# Session data.
session = {
'user':self.current_user['upn'],
'session':self.ws.session
}
# Sending message via webscoket.
message = {
'terminal:mypluginjs_sync_session':session
}
self.write_message(message)
# Plugin hooks.
hooks = {
'WebSocket': {
'terminal:myplugin_get_session':get_session
}
}
myphp app.
$auth = array(
'api_key' => $api_key,
'upn' => $user_name,
'timestamp' => time().'0000',
'signature_method' => 'HMAC-SHA1',
'api_version' => '1.0'
);
$webssh_auth['signature'] = hash_hmac('sha1',$auth['api_key'].$auth['upn'].$auth['timestamp'],$secret_key);
?>
<script>
var url = '<?php print $base_url ?>';
scriptTag = document.createElement('script');
scriptTag.src = url + '/static/gateone.js';
scriptTag.onload = function() {
GateOne.init({
url:url,
embedded:false,
disableTermTransitions:true,
showTitle:false,
showToolbar:false,
fillContainer:true,
colors:'gnome-terminal',
auth:<?php print json_encode($auth)?>,
autoConnectURL:'ssh://<?php print $user ?>@<?php print $host ?>:22' // autoconnect url not working, i posted #226 issue.
});
GateOne.MyPlugin.settings['url'] = '<?php print $myphpapp_url ?>'; // Throws undefined in console.
GateOne.MyPlugin.getSession(); // Throws undefined in console.
}
document.body.appendChild(scriptTag);
</script>
<div id="gateone"></div>
Im trying to execute my plugin functions after i init() gateone. From your above comments i experimented 'Events', it works but, not updating my plugin settings.
My questions, "Is it possible to create my own plugin settings such as GateOne.MyPlugin.settings object, and update in run time, by executing my plugin functions", "How do i send extra params from my php app to my plugin".
Any help?
You're getting that undefined exception because GateOne.MyPlugin had not yet loaded when GateOne.init() returned a result. This happens because JavaScript plugins are loaded on-the-fly in a semi-asynchronous manner. So if you wrapped your little GateOne.MyPlugin code in a setTimeout() around 2000ms that would probably work--but don't do that! I'm just saying that so you understand what's going on. There's "a better way":
I've modified your plugin and your initial page load script to pass in your plugin's settings to GateOne.init() and changed GateOne.MyPlugin.init() around a bit to be more reliable...
var url = '<?php print $base_url ?>';
scriptTag = document.createElement('script');
scriptTag.src = url + '/static/gateone.js';
scriptTag.onload = function() {
GateOne.init({
url:url,
embedded:false,
disableTermTransitions:true,
showTitle:false,
showToolbar:false,
fillContainer:true,
colors:'gnome-terminal',
auth:<?php print json_encode($auth)?>,
autoConnectURL:'ssh://<?php print $user ?>@<?php print $host ?>:22', // autoconnect url not working, i posted #226 issue.
myPluginSettings: {'url': '<?php print $myphpapp_url ?>'} // Put whatever you want in here
});
}
document.body.appendChild(scriptTag);
myplugin.js:
/**
* @file
* Plugin's main js file.
*/
(function(window, undefined) {
var document = window.document;
// Changing naming conventions.
var go = GateOne,
prefix = go.prefs.prefix,
u = go.Utils,
v = go.Visual,
E = go.Events,
t = go.Terminal,
urlObj = (window.URL || window.webkitURL),
logFatal = GateOne.Logging.logFatal,
logError = GateOne.Logging.logError,
logWarning = GateOne.Logging.logWarning,
logInfo = GateOne.Logging.logInfo,
logDebug = GateOne.Logging.logDebug;
// GateOne.MyPlugin object.
go.Base.module(GateOne, 'MyPlugin', '1.0', ['Base', 'Net']);
go.MyPlugin.settings = {'url': null}; // Scaffold object (not really necessary)
// This ensures that myPluginSettings doesn't get saved when the user clicks the "Save" button in their prefs
go.noSavePrefs['myPluginSettings'] = null;
// Internal properties of GateOne.MyPlugin object.
go.Base.update(go.MyPlugin, {
// Initializer.
init: function() {
// Set this plugin's settings from 'myPluginSettings' which can be passed in via GateOne.init()
go.MyPlugin.settings = go.prefs.myPluginSettings;
// By placing the call to getSession() here we can ensure it only gets called after the plugin is ready for use:
go.MyPlugin.getSession();
// Adding websocket actions.
go.Net.addAction('terminal:mypluginjs_sync_session', go.MyPlugin.syncSession);
},
getSession: function() {
// Calling server-side hook via WebSocket Action.
go.ws.send(JSON.stringify({'terminal:myplugin_get_session': true}));
},
syncSession: function(data) {
// My stuff goes here.
// Here's a better way to debug your incoming data:
logInfo(data); // Will be output to the JS console along with the date (which can be important if you need to know when something happened)
console.log(data); // This will allow you to explore the object in the JS console (nice GUI)
alert(JSON.stringify(data)); // This is just annoying if you ask me :)
alert(go.MyPlugin.settings['url']); // This always says 'null', but i'm updating this in my php app.
}
});
})(window);
Hopefully that answers your questions. There's more than one way to handle these kinds of things too (such as calling a WebSocket action from the server that initiates additional functions in your plugin). Let me know if you have any more questions.
Thanks for you effort Dan. Now i understood things a little better.
Now i'm able to pass php app settings into my plugin js easily. I implemented your workflow and tested the code, your solution works great. Thanks a lot.
I know lot of questions are going to arise from my head, when developing this plugin. Will ask you if anything serious. Anyway thanks a lot for you help.
Traditional way of loading a module in python is "import
Say for example, i want to use your 'ssh' python plugin's api function on my python plugin. I know i can do this by sys.path.append(
The sys.path for all plugins should be automatically added by Gate One. So you should be able to import any plugin from within any plugin. Is that not working?
Yes, its not working Dan. I have raised an issue at https://github.com/liftoff/GateOne/issues/231. Please take a look at it.
Thanks. Need help on this.
Oh, sorry it my mistake. I haven't imported the tornado dependencies, thats why it didn't work. Fixed, now import works fine.
By the way, is there any way to destroy session, using gateone api. Tried kill_session(), but its not removing the session directory.
I don't find that sessions directory is getting cleaned up by session timeout also. Need help on this....
The sessions directory normally only gets cleaned up when gateone.py exits. Even then it won't clean it up if you're using dtach since dtach'd sessions could still be running in the background. It shouldn't be a big deal though... If you don't have any sessions running all you'll have in there is a bunch of empty directories. Even if you had thousands it shouldn't take up much space.
Yeah i know that sessions directory will be removed if gateone.py exists. I'm not using dtach and i got removed sessions programatically. Anyway my problem got solved. Thanks for reply.
Thanks
Hi Dan, as you know that i'm doing some R&D on building plugin for GateOne's terminal app. I'm trying to manipulate gateone's session data in my php code. Now I can able to load and exit Terminal successfully with my php code.
Whenever i pass autoconnect ssh url for first time using GateOne.init(), my terminal gets connected with it and within the sessions directory i can see a shell script named 'ssh:1:user@server'. Note that i'm running everything in embedded mode.
My problem is when i accidentially close the browser, and try to load a new terminal with the same autoconnect ssh url, my terminal gets connected to the old ssh script 'ssh:1:user@server' and not launching a new ssh connection. Also the autoconnect url gets populated but no use with that and looks ugly.
Is there any way to destroy the old ssh connection i.e 'ssh:1:user@server' and attach a new fresh ssh connection with my loaded terminal. The terminal number will always be 1, because i'm in embedded mode.
Please suggest me a programmatic way to accomplish this. I'm constantly reading code and have already tried some few idea's using GateOne's API but no luck till now.
Thanks in advance...
I tried to build a plugin to extend GateOne, but dont have any luck on it. Is there anybody, who built a plugin for Gateone??
Also i want to know how to override existing hooks?. I found a example plugin, but it does'nt really state anything about the workflow in a plugin.
How do i integrate my Websocket hooks in python with javascript ??.
Any help would be appreciated!!! Thanks.