private void gridApps_MouseClick(object sender, MouseEventArgs e) { var hti = gridApps.HitTest(e.X, e.Y); int currentRow = hti.RowIndex; int currentCol = hti.ColumnIndex; var plan = ctrl.GetCurrentPlan(); var planAppDefsDict = (plan != null) ? (from ad in plan.getAppDefs() select ad).ToDictionary(ad => ad.AppIdTuple, ad => ad) : new Dictionary <AppIdTuple, AppDef>(); if (currentRow >= 0) // ignore header clicks { DataGridViewRow focused = gridApps.Rows[currentRow]; var appIdTuple = new AppIdTuple(focused.Cells[0].Value as string); var st = ctrl.GetAppState(appIdTuple); bool connected = callbacks.isConnectedDeleg(); bool isLocalApp = appIdTuple.MachineId == this.machineId; bool isAccessible = isLocalApp || connected; // can we change its state? var appDef = planAppDefsDict.ContainsKey(appIdTuple) ? planAppDefsDict[appIdTuple] : null; if (e.Button == MouseButtons.Right) { // build popup menu var popup = new System.Windows.Forms.ContextMenuStrip(this.components); popup.Enabled = connected || allowLocalIfDisconnected; var launchItem = new System.Windows.Forms.ToolStripMenuItem("&Launch"); launchItem.Click += (s, a) => guardedOp(() => ctrl.LaunchApp(appIdTuple)); launchItem.Enabled = isAccessible && !st.Running; popup.Items.Add(launchItem); var killItem = new System.Windows.Forms.ToolStripMenuItem("&Kill"); killItem.Click += (s, a) => guardedOp(() => ctrl.KillApp(appIdTuple)); killItem.Enabled = isAccessible && st.Running; popup.Items.Add(killItem); var restartItem = new System.Windows.Forms.ToolStripMenuItem("&Restart"); restartItem.Click += (s, a) => guardedOp(() => ctrl.RestartApp(appIdTuple)); restartItem.Enabled = isAccessible && st.Running; popup.Items.Add(restartItem); if (appDef != null && appDef.Disabled) { var setEnabledItem = new System.Windows.Forms.ToolStripMenuItem("&Enable"); setEnabledItem.Click += (s, a) => guardedOp(() => ctrl.SetAppEnabled(plan.Name, appIdTuple, true)); popup.Items.Add(setEnabledItem); } if (appDef != null && !appDef.Disabled) { var setEnabledItem = new System.Windows.Forms.ToolStripMenuItem("&Disable"); setEnabledItem.Click += (s, a) => guardedOp(() => ctrl.SetAppEnabled(plan.Name, appIdTuple, false)); popup.Items.Add(setEnabledItem); } popup.Show(Cursor.Position); } else if (e.Button == MouseButtons.Left) { // icon clicks if (currentCol == appTabColIconStart) { if (isAccessible && !st.Running) { guardedOp(() => ctrl.LaunchApp(appIdTuple)); } } if (currentCol == appTabColIconKill) { if (isAccessible && st.Running) { guardedOp(() => ctrl.KillApp(appIdTuple)); } } if (currentCol == appTabColIconRestart) { if (isAccessible && st.Running) { guardedOp(() => ctrl.RestartApp(appIdTuple)); } } if (currentCol == appTabColEnabled) { var wasEnabled = (bool)focused.Cells[currentCol].Value; if (plan != null) { guardedOp(() => ctrl.SetAppEnabled(plan.Name, appIdTuple, !wasEnabled)); } else { //MessageBox.Show("Application is not part of selected plan. Select a different plan!", "Dirigent", MessageBoxButtons.OK, MessageBoxIcon.Information); } } } } }
string getAppStatusCode(AppIdTuple appIdTuple, AppState st, bool isPartOfPlan) { string stCode = "Not running"; bool connected = callbacks.isConnectedDeleg(); var currTime = DateTime.UtcNow; bool isRemoteApp = appIdTuple.MachineId != this.machineId; if (isRemoteApp && !connected) { stCode = "??? (discon.)"; return(stCode); } var currPlan = ctrl.GetCurrentPlan(); if (currPlan != null) { var planState = ctrl.GetPlanState(currPlan.Name); bool planRunning = (currPlan != null) && planState.Running && isPartOfPlan; if (planRunning && !st.PlanApplied && !st.Disabled) { stCode = "Planned"; } } if (st.Started) { if (st.Running && !st.Initialized) { stCode = "Initializing"; } if (st.Running && st.Initialized) { stCode = "Running"; } if (!st.Running) { if (st.Killed) { stCode = "Killed"; } else { stCode = string.Format("Terminated ({0})", st.ExitCode); } } } else if (st.StartFailed) { stCode = "Failed to start"; } var statusInfoAge = currTime - st.LastChange; if (isRemoteApp && statusInfoAge > TimeSpan.FromSeconds(3)) { stCode += string.Format(" (Offline for {0:0} sec)", statusInfoAge.TotalSeconds); } return(stCode); }
public SetAppEnabledMessage(string planName, AppIdTuple appIdTuple, bool enabled) { this.planName = planName; this.appIdTuple = appIdTuple; this.enabled = enabled; }
public LaunchAppMessage(AppIdTuple appIdTuple) { this.appIdTuple = appIdTuple; }
public KillAppMessage(AppIdTuple appIdTuple) { this.appIdTuple = appIdTuple; }
public RestartAppMessage(AppIdTuple appIdTuple) { this.appIdTuple = appIdTuple; }
private void gridApps_MouseClick(object sender, MouseEventArgs e) { var hti = gridApps.HitTest(e.X, e.Y); int currentRow = hti.RowIndex; int currentCol = hti.ColumnIndex; var plan = _currentPlan; var planAppDefsDict = (plan != null) ? (from ad in plan.AppDefs select ad).ToDictionary(ad => ad.Id, ad => ad) : new Dictionary <AppIdTuple, AppDef>(); if (currentRow >= 0) // ignore header clicks { DataGridViewRow focused = gridApps.Rows[currentRow]; var id = new AppIdTuple(focused.Cells[0].Value as string); var st = _ctrl.GetAppState(id); bool connected = IsConnected; //bool isLocalApp = id.MachineId == this._machineId; bool isAccessible = connected; // can we change its state? var appDef = planAppDefsDict.ContainsKey(id) ? planAppDefsDict[id] : null; if (e.Button == MouseButtons.Right) { // build popup menu var popup = new System.Windows.Forms.ContextMenuStrip(this.components); popup.Enabled = connected || _allowLocalIfDisconnected; var launchItem = new System.Windows.Forms.ToolStripMenuItem("&Launch"); launchItem.Click += (s, a) => guardedOp(() => _ctrl.Send(new Net.StartAppMessage( _ctrl.Name, id, Tools.IsAppInPlan(_ctrl, id, _currentPlan) ? _currentPlan.Name : null // prefer selected plan over others ))); launchItem.Enabled = isAccessible && !st.Running; popup.Items.Add(launchItem); var killItem = new System.Windows.Forms.ToolStripMenuItem("&Kill"); killItem.Click += (s, a) => guardedOp(() => _ctrl.Send(new Net.KillAppMessage(_ctrl.Name, id))); killItem.Enabled = isAccessible && (st.Running || st.Restarting); popup.Items.Add(killItem); var restartItem = new System.Windows.Forms.ToolStripMenuItem("&Restart"); restartItem.Click += (s, a) => guardedOp(() => _ctrl.Send(new Net.RestartAppMessage(_ctrl.Name, id))); restartItem.Enabled = isAccessible; // && st.Running; popup.Items.Add(restartItem); if (appDef != null && appDef.Disabled) { var setEnabledItem = new System.Windows.Forms.ToolStripMenuItem("&Enable"); setEnabledItem.Click += (s, a) => guardedOp(() => _ctrl.Send(new Net.SetAppEnabledMessage(_ctrl.Name, plan.Name, id, true))); popup.Items.Add(setEnabledItem); } if (appDef != null) { var setEnabledItem = new System.Windows.Forms.ToolStripMenuItem("&Disable"); setEnabledItem.Click += (s, a) => guardedOp(() => _ctrl.Send(new Net.SetAppEnabledMessage(_ctrl.Name, plan.Name, id, false))); popup.Items.Add(setEnabledItem); } //var propsItem = new System.Windows.Forms.ToolStripMenuItem( "&Properties" ); //propsItem.Click += ( s, a ) => guardedOp( () => //{ // try{ // var appDef = planAppDefsDict.ContainsKey( id ) ? planAppDefsDict[id] : null; // var serializer = new System.Runtime.Serialization.DataContractSerializer(typeof(AppDef)); // using var sw = new StringWriter(); // using var writer = new System.Xml.XmlTextWriter(sw); // writer.Formatting = System.Xml.Formatting.Indented; // indent the Xml so it's human readable // serializer.WriteObject(writer, appDef); // writer.Flush(); // var xmlString = sw.ToString(); // MessageBox.Show(xmlString); // } catch( Exception ex ) // { // int i =1; // } //}); //propsItem.Enabled = true; //popup.Items.Add( propsItem ); popup.Show(Cursor.Position); } else if (e.Button == MouseButtons.Left) { // icon clicks if (currentCol == appTabColIconStart) { if (isAccessible) // && !st.Running ) { guardedOp(() => _ctrl.Send(new Net.StartAppMessage( _ctrl.Name, id, Tools.IsAppInPlan(_ctrl, id, _currentPlan) ? _currentPlan.Name : null // prefer selected plan over others ))); } } if (currentCol == appTabColIconKill) { if (isAccessible) // && st.Running ) { guardedOp(() => _ctrl.Send(new Net.KillAppMessage(_ctrl.Name, id))); } } if (currentCol == appTabColIconRestart) { if (isAccessible) // && st.Running ) { guardedOp(() => _ctrl.Send(new Net.RestartAppMessage(_ctrl.Name, id))); } } if (currentCol == appTabColEnabled) { var wasEnabled = ( bool )focused.Cells[currentCol].Value; if (plan != null) { guardedOp(() => _ctrl.Send(new Net.SetAppEnabledMessage(_ctrl.Name, plan.Name, id, !wasEnabled))); } else { //MessageBox.Show("Application is not part of selected plan. Select a different plan!", "Dirigent", MessageBoxButtons.OK, MessageBoxIcon.Information); } } } } }
/// <summary> /// Update the list of apps by doing minimal changes to avoid losing focus. /// Adding what is not yet there and deleting what has disappeared. /// </summary> void refreshAppList_smart() { DataGridViewRow selected = null; var plan = _currentPlan; var planAppDefsDict = (plan != null) ? (from ad in plan.AppDefs select ad).ToDictionary(ad => ad.Id, ad => ad) : new Dictionary <AppIdTuple, AppDef>(); var planAppIdTuples = (plan != null) ? (from ad in plan.AppDefs select ad.Id).ToList() : new List <AppIdTuple>(); Dictionary <AppIdTuple, AppState> appStates; if (ShowJustAppFromCurrentPlan) { appStates = (from i in _ctrl.GetAllAppStates() where planAppIdTuples.Contains(i.Key) select i).ToDictionary(mc => mc.Key, mc => mc.Value); } else // show from all plans { appStates = new Dictionary <AppIdTuple, AppState>(_ctrl.GetAllAppStates()); } // remember apps from plan Dictionary <string, AppIdTuple> newApps = new Dictionary <string, AppIdTuple>(); foreach (AppIdTuple a in appStates.Keys) { newApps[a.ToString()] = a; } // remember apps from list Dictionary <string, DataGridViewRow> oldApps = new Dictionary <string, DataGridViewRow>(); foreach (DataGridViewRow item in gridApps.Rows) { string id = item.Cells[appTabColName].Value as string; oldApps[id] = item; if (item.Selected) { if (selected == null) { selected = item; } } } // determine what to add and what to remove List <DataGridViewRow> toRemove = new List <DataGridViewRow>(); List <object[]> toAdd = new List <object[]>(); foreach (DataGridViewRow item in gridApps.Rows) { string id = item.Cells[0].Value as string; if (!newApps.ContainsKey(id)) { toRemove.Add(item); } } foreach (var x in appStates) { var idStr = x.Key.ToString(); if (!oldApps.ContainsKey(idStr)) { var id = x.Key; var appState = x.Value; var item = new object[appTabNumCols]; item[appTabColName] = idStr; //item[appTabColStatus] = getAppStatusCode( id, appState, planAppIdTuples.Contains( id ) ); item[appTabColStatus] = Tools.GetAppStateText(appState, _ctrl.GetPlanState(appState.PlanName), _ctrl.GetAppDef(id)); item[appTabColIconStart] = ResizeImage(new Bitmap(Resource1.play), new Size(20, 20)); item[appTabColIconKill] = ResizeImage(new Bitmap(Resource1.delete), new Size(20, 20)); item[appTabColIconRestart] = ResizeImage(new Bitmap(Resource1.refresh), new Size(20, 20)); item[appTabColEnabled] = false; item[appTabColPlan] = GetPlanForApp(id); toAdd.Add(item); } } foreach (var i in toRemove) { gridApps.Rows.Remove(i); } foreach (var i in toAdd) { gridApps.Rows.Add(i); } Dictionary <DataGridViewRow, UPD> toUpdate = new Dictionary <DataGridViewRow, UPD>(); foreach (var o in oldApps) { if (!toRemove.Contains(o.Value)) { var id = newApps[o.Key]; var appState = _ctrl.GetAppState(id); var upd = new UPD() { //Status = getAppStatusCode( id, appState, planAppIdTuples.Contains( id ) ), Status = Tools.GetAppStateText(appState, _ctrl.GetPlanState(appState.PlanName), _ctrl.GetAppDef(id)), PlanName = null }; if (appState.PlanName != null) { upd.PlanName = appState.PlanName; } toUpdate[o.Value] = upd; } } foreach (var tu in toUpdate) { var row = tu.Key; var upd = tu.Value; row.Cells[appTabColStatus].Value = upd.Status; if (upd.PlanName != null) { row.Cells[appTabColPlan].Value = upd.PlanName; } } // colorize the background of items from current plan List <string> planAppIds = (from ad in planAppIdTuples select ad.ToString()).ToList(); foreach (DataGridViewRow item in gridApps.Rows) { string idStr = item.Cells[0].Value as string; var id = AppIdTuple.fromString(idStr, ""); if (planAppIds.Contains(idStr)) { item.DefaultCellStyle.BackColor = Color.LightGoldenrodYellow; } else { item.DefaultCellStyle.BackColor = SystemColors.Control; } // set checkbox based on Enabled attribute od the appDef from current plan var appDef = planAppDefsDict.ContainsKey(id) ? planAppDefsDict[id] : null; { var chkCell = item.Cells[appTabColEnabled] as DataGridViewCheckBoxCell; chkCell.Value = appDef != null ? !appDef.Disabled : false; // emulate "Disabled" grayed appearance chkCell.FlatStyle = appDef != null ? FlatStyle.Standard : FlatStyle.Flat; chkCell.Style.ForeColor = appDef != null ? Color.Black : Color.DarkGray; chkCell.ReadOnly = appDef == null; } // put app state into a tooltip { var appStatusCell = item.Cells[appTabColStatus]; // as DataGridViewCell; appStatusCell.ToolTipText = Tools.GetAppStateString(id, _ctrl.GetAppState(id)); } } }
/// <summary> /// Sets new status info for given app. /// To be used for remote apps whose status gets received from master. /// </summary> /// <param name="appIdTuple"></param> /// <param name="appState"></param> public void SetRemoteAppState(AppIdTuple appIdTuple, AppState appState) { appsState[appIdTuple] = appState; }
private void gridApps_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) { var id = new AppIdTuple(( string )gridApps.Rows[e.RowIndex].Cells[appTabColName].Value); var cell = gridApps.Rows[e.RowIndex].Cells[e.ColumnIndex]; var defst = gridApps.Rows[e.RowIndex].Cells[appTabColName].Style; if (e.ColumnIndex == appTabColStatus) { var txt = gridApps.Rows[e.RowIndex].Cells[e.ColumnIndex].Value as string; if (txt.StartsWith("Running")) { cell.Style = new DataGridViewCellStyle { ForeColor = Color.DarkGreen, SelectionForeColor = Color.LightGreen, BackColor = defst.BackColor }; } else if (txt.StartsWith("Planned")) { cell.Style = new DataGridViewCellStyle { ForeColor = Color.DarkViolet, SelectionForeColor = Color.Violet, BackColor = defst.BackColor }; } else if (txt.StartsWith("Initializing")) { cell.Style = new DataGridViewCellStyle { ForeColor = Color.DarkOrange, SelectionForeColor = Color.Orange, BackColor = defst.BackColor }; } else if (txt.StartsWith("Terminated")) { var appDef = (from p in _ctrl.GetAllPlanDefs() from a in p.AppDefs where a.Id == id select a).FirstOrDefault(); if (appDef != null) { if (!appDef.Volatile) // just non-volatile apps are not supposed to terminate on their own... { cell.Style = new DataGridViewCellStyle { ForeColor = Color.Red, SelectionForeColor = Color.Red, BackColor = defst.BackColor }; } else { cell.Style = defst; } } else { cell.Style = defst; } } else if (txt.StartsWith("Restarting") || txt.StartsWith("Dying")) { cell.Style = new DataGridViewCellStyle { ForeColor = Color.Blue, SelectionForeColor = Color.Blue, BackColor = defst.BackColor }; } else { cell.Style = defst; } } }
public void RestartApp(AppIdTuple appIdTuple) { KillApp(appIdTuple); LaunchApp(appIdTuple); }
/// <summary> /// Launches a local app if not already running. /// </summary> /// <param name="appIdTuple"></param> public void LaunchApp(AppIdTuple appIdTuple) { if (!(localApps.ContainsKey(appIdTuple))) { throw new NotALocalApp(appIdTuple, machineId); } var la = localApps[appIdTuple]; var appState = appsState[la.AppDef.AppIdTuple]; // don't do anything if the app is already running if (la.launcher != null && la.launcher.Running) { return; } log.DebugFormat("Launching app {0}", la.AppDef.AppIdTuple); // launch the application appState.Started = false; appState.StartFailed = false; appState.Killed = false; la.watchers.Clear(); la.launcher = launcherFactory.createLauncher(la.AppDef, rootForRelativePaths); try { la.launcher.Launch(); appState.Started = true; appState.Initialized = true; // a watcher can set it to false upon its creation if it works like an AppInitDetector //// instantiate app watchers //foreach( var watcherDef in la.AppDef.Watchers ) //{ // var w = appWatcherFactory.create( la.AppDef, appsState[appIdTuple], la.launcher.ProcessId, watcherDef); // la.watchers.Add( w ); //} // instantiate init detector (also a watcher) { // compatibility with InitialCondition="timeout 2.0" ... convert to XML definition <timeout>2.0</timeout> { if (!string.IsNullOrEmpty(la.AppDef.InitializedCondition)) { string name; string args; AppInitializedDetectorFactory.ParseDefinitionString(la.AppDef.InitializedCondition, out name, out args); string xmlString = string.Format("<{0}>{1}</{0}>", name, args); var aid = appAppInitializedDetectorFactory.create(la.AppDef, appsState[appIdTuple], la.launcher.ProcessId, XElement.Parse(xmlString)); log.DebugFormat("Adding InitDetector {0}, pid {1}", aid.GetType().Name, la.launcher.ProcessId); la.watchers.Add(aid); } } foreach (var xml in la.AppDef.InitDetectors) { var aid = appAppInitializedDetectorFactory.create(la.AppDef, appsState[appIdTuple], la.launcher.ProcessId, XElement.Parse(xml)); log.DebugFormat("Adding InitDetector {0}, pid {1}", aid.GetType().Name, la.launcher.ProcessId); la.watchers.Add(aid); } } // instantiate window positioners foreach (var xml in la.AppDef.WindowPosXml) { log.DebugFormat("Adding WindowsPositioner, pid {0}", la.launcher.ProcessId); var wpo = new WindowPositioner(la.AppDef, appsState[appIdTuple], la.launcher.ProcessId, XElement.Parse(xml)); la.watchers.Add(wpo); } // instantiate autorestarter if (la.AppDef.RestartOnCrash) { log.DebugFormat("Adding AutoRestarter, pid {0}", la.launcher.ProcessId); var ar = new AutoRestarter(la.AppDef, appsState[appIdTuple], la.launcher.ProcessId, new XElement("Autorestart")); la.watchers.Add(ar); } } catch (Exception ex) // app launching failed { log.ErrorFormat("Exception: App \"{0}\"start failure {1}", la.AppDef.AppIdTuple, ex); appState.StartFailed = true; throw; } }
public void makeInitialized(AppIdTuple id) { makeLaunched(id); appsState[id].Initialized = true; }
public void makeLaunched(AppIdTuple id) { appsState[id].PlanApplied = true; appsState[id].Started = true; appsState[id].Running = true; }
/// <summary> /// Builds the list of waves as the result of application interdependencies. /// /// The first wawe will contain apps that do not depend on any other app. /// The second wave will contain the apps that depend on those from the first wave. /// Etc. untill all apps are processed. /// </summary> public static List <AppWave> build(IEnumerable <AppDef> launchPlan) { // seznam zbyvajicich aplikaci // seznam uz pouzitych aplikaci (ktere uz byly vlozeny do vln) // Prochazim seznam zbylych aplikaci a pro kazdou hledam, zda vsechny jeji zavislosti uz se nachazi // v seznamu pouzitych aplikaci. Pokud ano, zkopiruju aplikaci do aktualni vlny. Pro projiti // vsech aplikaci pak vezmu aplikace z aktulne vytvorene vlny, smazu je ze zbyvajicich a vlozim do pouzitych. List <AppDef> remaining = (from t in launchPlan where !t.Disabled select t).ToList(); // those not yet moved to any of the waves List <AppDef> used = new List <AppDef>(); // those already moved to some of waves // allow fast lookup of appdef by its name Dictionary <AppIdTuple, AppDef> dictApps = new Dictionary <AppIdTuple, AppDef>(); foreach (var app in remaining) { dictApps[app.AppIdTuple] = app; } var waves = new List <AppWave>(); // the resulting list of waves // For each of the remaining apps check whether all its dependencias were already moved to some of prevoiusly // built waves; if so, add the app to the current wave and move it from remaining to used. while (remaining.Count > 0) { List <AppDef> currentWave = new List <AppDef>(); // the wave currently being built foreach (var app in remaining) { bool allDepsSatisfied = true; if (app.Dependencies != null) { foreach (var depName in app.Dependencies) { AppIdTuple depId = AppIdTuple.fromString(depName, app.AppIdTuple.MachineId); if (!dictApps.ContainsKey(depId)) { // throw exception "Unknown dependency" throw new UnknownDependencyException(depName); } var dep = dictApps[depId]; if (!used.Contains(dep)) { allDepsSatisfied = false; break; } } } if (allDepsSatisfied) { currentWave.Add(app); } } // if there are no app in current wave, there must be some circular dependency // as there is no app that does not depend on if (currentWave.Count == 0) { // throw exception "Circular dependency somewhere" throw new CircularDependencyException(); } // move apps that were added to the current wave from remaining to used foreach (var app in currentWave) { remaining.Remove(app); used.Add(app); } // add current wave to the resulting list of wawes waves.Add(new AppWave(currentWave)); } return(waves); }