How to overcome caching issue when downloading data from internet using CHttpFile - http

This is how I currently download a ZIP file from the internet in my MFC project:
strTargetZIP = theApp.GetWorkingPath() + _T("AutoUpdate\\MWBDataUpdate.zip");
strDownloadURL = _T("https://www.publictalksoftware.co.uk/mwbdata/MWBDataUpdate.zip");
// ask user to go on line
const BOOL bOnline = InternetGoOnline(strDownloadURL.GetBuffer(), hWnd, 0);
strDownloadURL.ReleaseBuffer();
if (!bOnline)
return false;
try
{
// our session should already be open
// try to open up Internet session to my URL
// Use flag INTERNET_FLAG_RELOAD
pWebFile = dynamic_cast<CHttpFile*>(iSession.OpenURL(strDownloadURL, 1,
INTERNET_FLAG_SECURE | INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD));
if (pWebFile != nullptr)
{
if (pWebFile->QueryInfoStatusCode(dwStatusCode))
{
// 20x codes mean success
if ((dwStatusCode / 100) == 2)
{
if (fileLocal.Open(strTargetZIP,
CFile::modeCreate | CFile::modeWrite | CFile::typeBinary))
{
iRead = pWebFile->Read(&szBuffer[0], 4096);
while (iRead > 0)
{
iBytesRead += iRead;
fileLocal.Write(&szBuffer[0], iRead);
iRead = pWebFile->Read(&szBuffer[0], 4096);
}
fileLocal.Close();
bOK = true;
}
}
else
{
// There was a problem!
strError.Format(IDS_TPL_INVALID_URL, dwStatusCode);
AfxMessageBox(strError, MB_OK | MB_ICONERROR);
}
}
}
else
{
// Note, there is no error log. Use new error message?
AfxMessageBox(IDS_STR_UPDATE_CHECK_ERR, MB_OK | MB_ICONERROR);
}
}
catch(CException *e_)
{
const gsl::not_null<CException*> e{ e_ };
e->ReportError();
e->Delete();
}
As you can see, I have tried to cater for caching issues. However, it seems that on occasion, for some users, the software does not download the latest ZIP and uses a cached version.
What further steps can I as a developer (or they as a user) take to ensure that my software does actually download the latest ZIP file on my website server?

Related

Flutter Firebase offline issues with await

When I try to reorder things in my reorderable list view, I run into a problem. If the user is online, awaiting the document references (as seen in the code) runs fast enough. The problem is, if the user is offline, the Firebase await function can take upwards of 20 seconds. On the other hand, if I don't await these changes, and do multiple quick reorders, the resulting writes as soon as I go back online differ greatly from the "order" state that I have in the app.
Is there anything I can do that avoids awaiting?
I have thought about checking the online status and disabling this feature while offline or disabling the reorder function while the function awaits. Both seem like really bad solutions.
Thanks for the help, the code is below:
Future<void> reorderExercises(int oldIndex, int newIndex,
CollectionReference<AddExercise> whereToUpdateRef) async {
List<DocumentReference<AddExercise>> referenceList = [];
await whereToUpdateRef.orderBy(COLUMN_DAYSINDEX).get().then(
(value) => value.docs.forEach(
(element) {
referenceList.add(element.reference);
},
),
);
void _updateIndex(int _oldIndex, int _newIndex) {
referenceList[_oldIndex].update(
{COLUMN_DAYSINDEX: _newIndex},
);
}
if (oldIndex < newIndex) {
newIndex -= 1;
_updateIndex(oldIndex, newIndex);
for (int i = oldIndex + 1; i <= newIndex; i++) {
_updateIndex(i, i - 1);
}
} else {
for (int i = oldIndex - 1; i >= newIndex; i--) {
_updateIndex(i, i + 1);
}
_updateIndex(oldIndex, newIndex);
}
}
Problem:
await is very slow when the user has no internet on
Solution:
You check if the user has internet. if not you push to a noInternet() screen with a try again button.
You can check if the user have internet with this code:
Source _source = Source.serverAndCache;
try {
final result = await InternetAddress.lookup('example.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
_source = Source.serverAndCache;
}
} on SocketException catch (_) {
_source = Source.cache;
}
firebaseDocumentReference.get(GetOptions(source: _source))...
This is very close to Liam's answer, but I cannot edit it unfortunately.
Using his code I changed the source option and now offline await works as fast as online. Also changed "google.com" to "expample.com" for it to work in China as well.
Problem:
await is very slow when the user has no internet on
Solution:
You check if the user has internet. if not you push to a noInternet() screen with a try again button.
You can check if the user have internet with this code:
var haveInternet;
...
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
haveInternet = true;
}
} on SocketException catch (_) {
haveInternet = false;
}
Hope it helps!

Android 10 - unable to take PersistableUriPermission on a file that I created in getExternalFilesDir()

Using the below code snippet, we created a file in Android 10, in a sub-folder under getExternalFilesDir(). However, immediately after creation, if we try to take persistableUriPermission, it throws an exception "No such permission exists....".
We need that check to know if that file will be available for read later in a common utility, else we have to make a copy. Please let us know what we might be doing wrong and how to fix this. Appreciate your help.
ParcelFileDescriptor filePFD =
cxt.getContentResolver().openFileDescriptor(Uri.parse(pathFileToSend), "r");
FileDescriptor fd = filePFD.getFileDescriptor();
FileInputStream fIn = new FileInputStream(fd);
File fileBaseFolder = new File(Utils.GetRootDirectory().getAbsolutePath(), Utils.DESTINATION);
if (!fileBaseFolder.exists())
fileBaseFolder.mkdirs();
if (fileBaseFolder.exists()) {
File copyFile = new File(fileBaseFolder.getAbsolutePath(), nameOfFile);
FileOutputStream fOut = new FileOutputStream(copyFile);
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = fIn.read(data)) != -1) {
total += count;
fOut.write(data, 0, count);
}
fOut.close();
Uri copiedFileUri =
FileProvider.getUriForFile(cxt,
cxt.getString(R.string.file_provider_authority),
copyFile);
if (null != copiedFileUri)
{
try {
/*At this line, an exception is thrown - No persistable permissions exist.. */
cxt.getContentResolver().takePersistableUriPermission(copiedFileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
} catch (Exception e) {
e.printStackTrace();
}
}
takePersistableUriPermission() is for Uri values that you get from the Storage Access Framework (e.g., ACTION_OPEN_DOCUMENT). It will not work for FileProvider. And, you do not need permissions to work with getExternalFilesDir() on Android 4.4 and higher.

How to get network connection status in apple watch standalone application?

Using NWPathMonitor, I get network information in watch simulator (with usesInterfaceType) and it showing right status, but in real device it's not working. It alway showing no network. I developed independent watch application. Please check below code that I write for this:
let monitor = NWPathMonitor()
monitor.pathUpdateHandler = { path in
if path.status == .satisfied {
print("We're connected!")
if path.usesInterfaceType(.wifi) {
print("It's WiFi!")
} else if path.usesInterfaceType(.cellular) {
print("3G/4G FTW!!!")
} else if path.usesInterfaceType(.wiredEthernet) {
print("wiredEthernet")
}else if path.usesInterfaceType(.loopback) {
print("loopback")
}else if path.usesInterfaceType(.other) {
print("other")
}
}
else {
print("No connection.")
}
}
let queue = DispatchQueue(label: "InternetConnectionMonitor")
monitor.start(queue: queue)

Setting default TWAIN data source without using API UI menu

Using the twaindotnet library in C#, I'm wondering if there's a way to set the default datasource using the library.
As a feeble attempt, I've tried adding a SetDefault method to the DataSource class of twaindonet, like this
public static void SetDefault(Identity applicationId, IWindowsMessageHook messageHook, DataSource newDataSource)
{
var defaultSourceId = newDataSource.SourceId;
// Attempt to get information about the system default source
var result = Twain32Native.DsmIdentity(
applicationId,
IntPtr.Zero,
DataGroup.Control,
DataArgumentType.Identity,
Message.Set,
defaultSourceId);
if (result != TwainResult.Success)
{
var status = DataSourceManager.GetConditionCode(applicationId, null);
throw new TwainException("Error getting information about the default source: " + result, result, status);
}
}
which is called from the DataSourceManage class like this
public void SelectSource(DataSource dataSource)
{
DataSource.Dispose();
DataSource.SetDefault(ApplicationId, _messageHook, dataSource);
}
But when I try to use SetDefault, Twain32Native.DsmIdentity always results in Failure being returned.
I basically copied from SetDefault the setDefaultDataSource method from TWAIN sample Data Source and Application
pTW_IDENTITY TwainApp::setDefaultDataSource(unsigned int _index)
{
if(m_DSMState < 3)
{
cout << "You need to open the DSM first." << endl;
return NULL;
}
else if(m_DSMState > 3)
{
PrintCMDMessage("A source has already been opened, please close it first\n");
return NULL;
}
if(_index >= 0 && _index < m_DataSources.size())
{
m_pDataSource = &(m_DataSources[_index]);
// set the specific data source
TW_UINT16 twrc;
twrc = _DSM_Entry(
&m_MyInfo,
0,
DG_CONTROL,
DAT_IDENTITY,
MSG_SET,
(TW_MEMREF) m_pDataSource);
switch (twrc)
{
case TWRC_SUCCESS:
break;
case TWRC_FAILURE:
printError(0, "Failed to get the data source info!");
break;
}
}
else
{
return NULL;
}
return m_pDataSource;
}
Any help would be greatly appreciated.
The possible cause is that the version of your TWAIN DSM is too low. Only DSM 2.0 or above supports setting default TWAIN data source.

Document Scanning from ASP.net Web Application

I have a ASP.Net C# 4.0 Web Application
I need to Add a scanning feature for my users.
This is what I want to achieve
On my web application
user clicks on a button
opens a window with preview of document in Scanning device attached to the client system
User confirms the Scan
this will save the Scanned document in jpg/pdf format on the server
then do the OCR on document
Can any one suggest a way to achieve this.
I read about this https://www.leadtools.com/sdk/engine/imaging not sure how much this can work. Can any one suggest a best way to get this done.
Thanks
update
tried leadtools from https://www.leadtools.com/support/forum/posts/m28036-Re--Scan-and-Upload-v16--NET-with-Caspol-exe-deployment as LEAD Support suggested but it is missing references not sure where and how to get those references
HaBo,
This is LEAD support. Since you mentioned our LEADTOOLS toolkit, the answer to your question is yes. Our toolkit can be used to implement either of the 2 approaches mentioned by tgolisch.
For the click-once approach, you simply use our Windows Forms controls that contain Twain support and package your application for ClickOnce deployment. This is done, for example, in this demo project:
LEADTOOLS ClickOnce Demos
For the custom control approach, see the example code projects on our forums that perform Scan and Upload
Solution is here:
In ASP.Net/Core Project you send message to call winform project:
var start = function () {
var i = 0;
var wsImpl = window.WebSocket || window.MozWebSocket;
window.ws = new wsImpl('ws://localhost:8181/');
ws.onmessage = function (e) {
$('#submit').hide();
$('#scanBtn').hide();
$('.loader').show();
if (typeof e.data === "string") {
//IF Received Data is String
}
else if (e.data instanceof ArrayBuffer) {
//IF Received Data is ArrayBuffer
}
else if (e.data instanceof Blob) {
i++;
var f = e.data;
f.name = "File" + i;
storedFiles.push(f);
formdata.append(f.name, f);
var reader = new FileReader();
reader.onload = function (e) {
var html = "<div class=\"col-sm-2 text-center\"
style=\"border: 1px solid black; margin-left: 2px;\"><img
height=\"200px\" width=\"200px\" src=\"" + e.target.result + "\"
data-file='" + f.name + "' class='selFile' title='Click to
remove'><br/>" + i + "</div>";
selDiv.append(html);
$('#submit').show();
$('#scanBtn').show();
$('.loader').hide();
}
reader.readAsDataURL(f);
}
};
ws.onopen = function () {
//Do whatever u want when connected succesfully
};
ws.onclose = function () {
$('.dalert').modal('show');
};
}
window.onload = start;
function scanImage() {
ws.send("1100");
};
https://javascript.info/websocket
In Winforms Project you scan document and send graphic data back to Asp.Net/Core project:
public partial class Form1 : Form
{
ImageCodecInfo _tiffCodecInfo;
TwainSession _twain;
bool _stopScan;
bool _loadingCaps;
List allSockets;
WebSocketServer server;
public Form1()
{
InitializeComponent();
if (NTwain.PlatformInfo.Current.IsApp64Bit)
{
Text = Text + " (64bit)";
}
else
{
Text = Text + " (32bit)";
}
foreach (var enc in ImageCodecInfo.GetImageEncoders())
{
if (enc.MimeType == "image/tiff") { _tiffCodecInfo = enc; break; }
}
this.WindowState = FormWindowState.Minimized;
this.ShowInTaskbar = false;
allSockets = new List<IWebSocketConnection>();
server = new WebSocketServer("ws://0.0.0.0:8181");
server.Start(socket =>
{
socket.OnOpen = () =>
{
Console.WriteLine("Open!");
allSockets.Add(socket);
};
socket.OnClose = () =>
{
Console.WriteLine("Close!");
allSockets.Remove(socket);
};
socket.OnMessage = message =>
{
if (message == "1100")
{
this.Invoke(new Action(()=> {
this.WindowState = FormWindowState.Normal;
}));
}
};
});
}
Link to project.
https://github.com/mgriit/ScanAppForWeb
You can remake this project, as you want.
Web browsers don't have permissions to use system devices like this(major security issue). There are 2 common ways of getting around this:
Make a custom control to run in your browser (flash, silverlight, java applet).
Make a "click-once deployment app" that a user launches from your page.
Both approaches would send the data back to your server via web
services or WCF, etc.

Resources