I'm making a multi user remote administration tool, a sort of VNC but which support multi remote desktop viewer a bit like Teamviewer does.
I have a Delphi Form which only contains a TListview, this listview contains users list which are currently connected to the server.
When a connection is dropped, the listview item is deleted.
For some reason I got some random problems while deleting more than a single item, for example if I decide to flush the whole server connections, if I have more than 1 listview item, it start going crazy.
Sometimes no error show up, just some items remain listed, sometimes it shows "address violations errors".
As I was before using pure Winsock API to make Client / Server application, I maybe use badly Indy components.
A short explanation about my way of managing the Server component.
My application is Multi Server, which means user could create one or many servers at the same time.
When a new Server is created by the user it run a new thread which will create a new indy Server component and setup needed events (OnConnect, OnExecute, OnDisconnect) etc...
Every commands that acts with some VCL form are of course Synchronize using the Synchronize(); delphi method.
When a new connection show up, i create from the Server Execute method a new listview item, then i set the new listview item to the AContext.data property.
When a connection is dropped on the OnDisconnect event, I delete the listview item then empty the AContext data to be sure, he wont do it again when he will be automatically destroy.
Synchronize(procedure begin
TListItem(AContext.data).Delete;
end);
AContext.data := nil;
This way of doing works very badly when I have more than a single connection. After debugging it seems even with the Synchronize commands are executed at the same time which could result conflicts in the VCL form.
I'm not an expert in Indy10, any advice would be surely appreciate.
Usually it is not a good idea to store your data in the UI.
Alternative answer on how might want to organize this:
Store your users list in the business layer of your project.
Display the users using a virtual model listview that obtains the data from the business layer. See for instance the answer at https://stackoverflow.com/a/4233875/29290
Access that data in a thread safe manner (locking, etc)
In the Indy 10 thread, access the data in a thread safe manner (locking, etc)
Have the business layer notify the Indy and UI portions of changes in the data
Related
I need some help with umbraco.
Let's say that I have an umbraco grid with a custom editor, just like the one in this tutorial: https://our.umbraco.com/documentation/Getting-Started/Backoffice/Property-Editors/Built-in-Property-Editors/Grid-Layout/build-your-own-editor
Ok, so I wrote this editor to build a gallery of items with image/title, I get the item list from an api call made by an angular service and this works fine when I publish the page by hand. What I want is to automatically update this gallery with new items where available, so my idea was to make a timed ajax call, let's say every hour, to update the items. But sadly this doesn't work, I suppose that the call is made but the list isn't updated.
Any suggestion? Thanks
You need to handle this differently. Right now it sounds like what you have is an implementation that works when you are browsing to this node in the backoffice using your browser and the browser makes the API calls through Angular. This all happens in your UI and when you manually hit save/publish - the data in the UI gets saved. Keep in mind that this is basically your browser doing the "work" - and this (and all other Angular code) will of course only ever run while your browser is open, in the backoffice, viewing this node.
What you want to do is to have this run automatically (and preferably in some sort of background task) to ensure that you do not really have to open up the backoffice for this to actually be automatically updated over time.
You need to create some sort of background job running on the server-side instead. This would have to be done in C# and I would recommend looking into Hangfire or Quartz frameworks to handle all the scheduling/making sure the job runs.
This job/task should do the external API calls in C# and transform the result into the same format as the format you are saving when you save data from the manual update. Then fetch the content nodes you need to update using the ContentService API and update the specific property values on those nodes. When this is done you need to make sure the changes are saved and the node is then republished with its updated data. All of this is done through the ContentService.
I have page with table that populates data based on complex query(takes lot of time even though I use pagination). I use BeanItemcontainer to load data in to the table. Now coming to the problem, I wish to load the data in to the table in a async way(after the complete page gets loaded on the user screen. I wan to populate the data). Is there some thing like onPageLoad event or onPageRenderEvent or equivalent that I can use to achieve this?
Details -
Version - Vaadin -7.0
Component - Table
Data Container - BeanItemContainer.
There's a number of ways to solve this, but you have to decide how you want to approach the problem. Here's two that I know of:
1) Request from the client.
2) Push from the server. (technically still a request from the client)
1 -- A) Request from a Javascript function programmed on the client-side. Attach the component to a layout by using a Javascript Extension or a Javascript component and make requests by calling a server-side API function. You can then update the table within that request and not worry about syncing issues.
1 -- B) Make your own GWT / Vaadin widget (same thing, basically) to do 1A.
2 -- A) Request from a Vaadin component programmed on the "server-side." Make a visible (or invisible) progress indicator that polls the server. Populate the table in a background thread and Vaadin will send the data you've currently gathered. The progress indicator can do this many times and the table will only send the difference to the client-side code (called the delta). Be careful updating client-facing components from background threads; you need to sync on changes to the component to avoid concurrent modification errors.
2 -- B) Add a refresher to the application and follow 2A above without needing a progress indicator.
Either solution involves you explicitly updating the table, either in a background thread (2A,B) or in the server method called from the client (1A,B). And both are technically client-request based. The Vaadin team are working on adding true 'push.'
The Vaadin way to solve this problem is to use a lazy loading Container. There are several lazy loading containers available for Vaadin: SQLContainer in core, LazyQueryContainer and JPAContainer.
I developed an Client/Server application, using datasnap. I need to know how to refresh the data on the server whenever a client has updated a table. The reason being that when I run a query on the client, after I inserted records into a table, the new records do not reflect in the queries.
Im using a firebird db, with datasnap, developing in Delphi XE2
Put a TTimer control on the client form and specify refreshing time frequency, change interval value as your needs, for example:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
table1.refresh;
end;
I would say, it also depends on tools you are using to write to DB.But, generally, with Firebird, you would Activate a Transaction and once update is done you would then Commit your changes. Prior to committing, no other client can see the new Changes no matter how many times they refresh. Once committed, my understanding would be to say, you would then Refresh you data by merely calling a SELECT command, as per your criteria.
I have a bit of problem here. I have created a lookupfield in my application server using Delphi XE2 DataSnap technology. On the client side, that field becomes TStringField. Now, the problem is that I loose the lookup functionality on the client side. To top that, I can't change the stringfield on the client side because it is read only (even if I manually turn off the read only property).
I don't want to lookup tables on the client side because I don't want all the data loaded on my client side just to support look up.
I can change the Key field value, but the stringfield lookup text doesnt change unless I apply updates and reload the data.
Users want to see the text change.
What should I do?
Seems you have to review your GUI functionality: lookup fields are really an client side feature. And it needs the lookup source - so to use it on client the lookup table must be loaded. DataSnap guys are very nice here, converting it to an TStringField when transmitting it to the client... I would simply ignore it.
So, if the lookup table is that big, you shouldn't using lookup fields but search UIs - or autocomplete comboboxes which you do queries against the DataSnap Server. Maybe you have to code it manually in the combobox case, I don't know (see if JVCL have something you can use to shortcut the path).
Alternatively, if the lookup table are seldom updated, you can aggresively cache it and have an updating mechanism to detect changes. So you can use the lookup fields the way they were created for.
Long time ago i faced that problem and i found a solution that is a bit complex to analyze here but i try to give some guidelines till i have the time to write a detailed blog post.
The idea consists of info (concerning lookup fields such as field properties, datasets, providers) packaged by the provider as optionalparams at the server side.
At client side a derived TClientDataset can unpack and process these info, create on the fly client datasets that retrieve needed lookup datasets and setup it's lookup fields accordingly.
The process is transparent due to the embedded functionality in the derived client dataset class and the only things to remember is to create that info in the provider's OnGetDatasetProperties event and turn false all provider flags in lookup fields.
i'm developing a custom component, and i'd like to add a published property that would be an array of TQuery (it should be visible in the object inspector). the main feature would be to drop the component on a form and then visually select the queries that are present on the same form, or on any other project form.
is that doable? from what i've seen till now, you can only programatically use such an array property...
UPDATE
first, thanks for your answer Alex!
second, the chatch is that i have to modify an old app someone else created, so i want to tangle with it as little as possible (actually there's a second app i need to "fix" which i was told is twice as big). now for the details: the app has abou 15 forms for various db operations. as you can imagine each form has 2-3 TQuery objects. the problem is that the user must authenticate with the db in order to execute the queries, thus he knows the db user & pwd which is a security flow.
in order to avoid this, an intermediate system has been introduced. one connects & authenticates with it and requests the necessary db data: user, pwd, and database name. my job is to use this system and autologin to the db. the necessary credentials to access this intermediate system are not considered a security flow so i'll read them from an inifile that depends on the environment where it's deployed: test, pre-production, production.
so i placed a TDatabase component on my form, setting its LoginPrompt property to FALSE. the tricky part however is adjusting each TQuery to the diferent database name for each environment before execution..
dunno if i made myself clear but it's the simplest explaination i managed to come up with
thanks,
G
To make life as simple as possible, you may have to grin and bear it once:
Create a datamodule and make sure it gets instantiated before the main form.
Put your TDatabase component on that data module.
Go through all your forms once and
add the database's data module to its uses clause (can be in implementation section).
Change all your TQuery and other database related components once to use the database component from the data module instead of having their own connection strings.
At run time, login as you described via your TDatabase component et voila, all your components will now use these settings automagically (as they are all connected to your TDatabase instance).
Okay, you've added a TDatabase to your project. Now, fill the "DatabaseName" property of TDatabase with some random name. Every TQuery component in your project also has a "DatabaseName" property and fill in the same name in those properties! Now your database and all it's queries will be connected and you could use the TDatabase object to access them all.
Yes, it can be done but you will have to write your own Property editor with it's own input form to manage the data inside the array. There's plenty of information to be found online. And yes, you could create a component that checks for controls on it's parent, allowing you to access those.
But is it practical? Why do you need an array of TQuery components in design time? Maybe you need to rethink your design first, so you're absolutely sure that you need this functionality. (Besides, what's wrong with using a Data Module to contain your queries?)