Skip to content

Commit

Permalink
Finalize plugin interface; Add to documentation.
Browse files Browse the repository at this point in the history
  • Loading branch information
antony-jr committed Mar 28, 2020
1 parent 6fa32c1 commit a04e07a
Show file tree
Hide file tree
Showing 14 changed files with 369 additions and 8,539 deletions.
2 changes: 1 addition & 1 deletion docs/AddingAppImageUpdaterBridge.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
id: AddingAppImageUpdaterBridge
title: Add AppImage Updater Bridge to your Project
sidebar_label: Add AppImage Updater Bridge to your Project.
sidebar_label: Adding to your Project.
---

AppImage Updater Bridge can compiled with both *QMake* and *CMake* , I recommend you to use *QMake* if you are
Expand Down
14 changes: 8 additions & 6 deletions docs/ClassAppImageDeltaRevisioner.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ Eventhough all methods are reentrant , This class does not use **mutex** thanks
| void | [updateAvailable(bool, QJsonObject)](#void-updateavailablebool-qjsonobject) |
| void | [statusChanged(short)](#void-statuschangedshort) |
| void | [error(short)](#void-errorshort) |
| void | [progress(int, qint64, qint64, double, QString)](#void-progressint-percentage-qint64-bytesreceived-qint64-bytestotal-double-speed-qstring-speedunits) |
| void | [progress(int, qint64, qint64, double, QString)](#void-progressint-percentage--qint64-bytesreceived--qint64-bytestotal--double-speed--qstring-speedunits) |
| void | [logger(QString, QString)](#void-loggerqstring-qstring) |


Expand Down Expand Up @@ -310,11 +310,13 @@ The updater's progress is emitted through this unified signal.

**Where** ,

'percentage' is the percentage finished revising the latest AppImage.
'bytesReceived' is the received bytes of the latest AppImage.
'bytesTotal' is the total bytes of the latest AppImage.
'speed' is the transfer speed value.
'speedUnits' is the transfer speed unit(e.g. KiB/s , etc... ) for 'speed'.
| Variable | Description |
|----------------|------------------------------------------------------------------|
| percentage | % Finished revising the latest AppImage. |
| bytesReceived | The received bytes of the latest AppImage. |
| bytesTotal | The total bytes of the latest AppImage. |
| speed | The transfer speed value. |
| speedUnit | The transfer speed unit(e.g. KiB/s , etc... ) for **speed**. |


### void logger(QString , QString)
Expand Down
186 changes: 186 additions & 0 deletions docs/PluginInterface.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
---
id: PluginInterface
title: AppImage Updater Bridge Plugin Interface
sidebar_label: Qt Plugin Interface
---

A plugin interface is a specification of public slots and signals that can be used to access
the functionality of the plugin itself. The interface is not bound to any specific programming
language and easily translates to any Qt bindings and programming language.

All slots are [reentrant](https://doc.qt.io/qt-5/threads-reentrancy.html) and thread safe.

Please refer the C++ documentation for info on how the slots act.

> IMPORTANT: You have to start your Qt event loop for AppImageUpdaterBridge to function.
### A note on Data Types

Since plugins are not C++ specific, The data types are vaguely defined.
In dynamic languages like python, you can just use native data types. (i.e) For QString, you can use str or QString from your Qt binding itself.

I'm not sure about other Qt bindings, So help is much welcomed.

## Slots

| Name | Description |
|------|------------------------------------|
| [start()](#start) | Starts the update. |
| [cancel()](#cancel) | Cancels current update process. |
| [setAppImage(QString)](#setappimage-qstring) | Assume the given string as path to AppImage to update. |
| [setShowLog(bool)](#setshowlogbool) | If the given boolean is true then prints log. |
| [setOutputDirectory(QString)](#setoutputdirectory-qstring) | Set the output directory as given string. |
| [setProxy(QNetworkProxy)](#setproxyconst-qnetworkproxy-https-docqtio-qt-5-qnetworkproxyhtml) | Use proxy as given in QNetworkProxy object. |
| [checkForUpdate()](#checkforupdate) | Checks for new update. |
| [clear()](#clear) | Clears internal cache and stores. |

## Signals

| Name | Description |
|------|---------------|
| [started()](#started) | Emitted when the update is actually started. |
| [canceled()](#canceled) | Emitted when the update is canceled. |
| [finished(QJsonObject , QString)](#finishedqjsonobject-qstring) | Emitted when update finishes. |
| [updateAvailable(bool, QJsonObject)](#updateavailablebool-qjsonobject) | Emitted when checkForUpdate() is called. |
| [error(short)](#errorshort) | Emitted when some error occurs. |
| [progress(int, qint64, qint64, double, QString)](#progressint-percentage--qint64-bytesreceived--qint64-bytestotal--double-speed--qstring-speedunits) | Emitted on progress of update. See here for more information. |
| [logger(QString, QString)](#loggerqstring-qstring) | See here for more information. |


## Documentation

### start()
<p align="right"> <b>[SLOT]</b> </p>

Starts the updater.
Emits **started()** signal when starts.


> Minor Note: You don't have to worry about anything if you called checkForUpdate or getAppImageEmbededInformation
slots before start , Don't worry about overheads too , Since when you call checkForUpdate slot , The information
is cached and when start slot is called again , it will be faster than normal.

> Important Note: You should also call clear and set the settings again if you want to clear the cache.
### cancel()
<p align="right"> <b>[SLOT]</b> </p>

Cancels the update.
Emits **canceled()** signal when cancel was successfull.


### setAppImage(QString)
<p align="right"> <b>[SLOT]</b> </p>

Sets the AppImage Path as the given **QString**.


### setShowLog(bool)
<p align="right"> <b>[SLOT]</b> </p>

Turns on and off the log printer.

> Note: logger signal will be emitted all the time if the library is compiled with LOGGING_DISABLED undefined,
setShowLog will not affect this activity at all, But setShowLog will print these log messages
if set to true.

### setOutputDirectory(QString)
<p align="right"> <b>[SLOT]</b> </p>

Writes the new version of the AppImage to the given Output directory , Assuming the given QString a directory path.
The default is the old version AppImage's directory.


### setProxy([QNetworkProxy](https://doc.qt.io/qt-5/qnetworkproxy.html))
<p align="right"> <b>[SLOT]</b> </p>

Sets the given [QNetworkProxy](https://doc.qt.io/qt-5/qnetworkproxy.html) as the proxy

### checkForUpdate()
<p align="right"> <b>[SLOT]</b> </p>

Checks update for the current operating AppImage.
emits **updateAvailable(bool , QJsonObject)** , Where the *bool* will be **true** if the AppImage
needs update. The QJsonObject in the signal will have the details of the current operating
AppImage.


### clear()
<p align="right"> <b>[SLOT]</b> </p>

Clears all internal **cache** and stores.


### started()
<p align="right"> <b>[SIGNAL]</b> </p>

Emitted when the updater is started successfully.

### canceled()
<p align="right"> <b>[SIGNAL]</b> </p>

Emitted when the update is canceled successfully.

### finished(QJsonObject , QString)
<p align="right"> <b>[SIGNAL]</b> </p>

Emitted when the update is finished successfully. The given *QJsonObject* has the details of the new version
of the AppImage and the given *QString* has the absolute path to the old versioin of the AppImage.

The *QJsonObject* will follow the folloing format with respect to json ,

{
"AbsolutePath" : "Absolute path of the new version of the AppImage" ,
"Sha1Hash" : "Sha1 hash of the new version of the AppImage"
}

> Note: If the absolute path of the new version of the AppImage is same as the old version then
it could mean that there were no updates needed , You can however listen to the *updateAvailable*
signal to know the exact state of updates. You should call *checkForUpdate* and then call *start*
if updates were really available.


### updateAvailable(bool , QJsonObject)
<p align="right"> <b>[SIGNAL]</b> </p>

Emitted when *[checkForUpdate()](#checkforupdate)* is called.
The given *bool* states if the operating AppImage needs update and the *QJsonObject* gives the details of
the current operating AppImage.

The *QJsonObject* will follow the following format with respect to json ,

{
"AbsolutePath" : "The absolute path of the current operating AppImage" ,
"Sha1Hash" : "The Sha1 hash of the current operating AppImage" ,
"RemoteSha1Hash" : "The Sha1 hash of the lastest AppImage" ,
"ReleaseNotes" : "Release notes if available"
}

### error(short)
<p align="right"> <b>[SIGNAL]</b> </p>

Emitted when the updater is errored. The given short integer is the error code.
See [error codes](AppImageUpdaterBridgeErrorCodes.html).


### progress(int percentage , qint64 bytesReceived , qint64 bytesTotal , double speed , QString speedUnits)
<p align="right"> <b>[SIGNAL]</b> </p>

The updater's progress is emitted through this unified signal.

**Where** ,

| Variable | Description |
|----------------|------------------------------------------------------------------|
| percentage | % Finished revising the latest AppImage. |
| bytesReceived | The received bytes of the latest AppImage. |
| bytesTotal | The total bytes of the latest AppImage. |
| speed | The transfer speed value. |
| speedUnit | The transfer speed unit(e.g. KiB/s , etc... ) for **speed**. |

### logger(QString , QString)
<p align="right"> <b>[SIGNAL]</b> </p>

Emitted when the updater issues a log message with the *first QString* as the log message and
the *second QString* as the path to the respective AppImage.

95 changes: 95 additions & 0 deletions docs/PyQt5PluginExample.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
---
id: PyQt5PluginExample
title: Using AppImage Updater Bridge Plugin in PyQt5
sidebar_label: Using Plugin in PyQt5
---

This guide Demonstrates how to use the *AppImageUpdaterBridge* plugin to update a single AppImage file.
This example assumes you are using PyQt5 as your python binding to Qt framework.

> Note that if the plugin is placed in the predefined Qt Plugin path, then you don't need the
> absolute path of the plugin. Simply set the file name to 'libAppImageUpdaterBridge'.

## Building the Plugin

```
$ git clone https://github.com/antony-jr/AppImageUpdaterBridge
$ cd AppImageUpdaterBridge
$ mkdir build
$ cd build
$ cmake -DBUILD_AS_PLUGIN ..
$ make -j$(nproc)
$ export PLUGIN_PATH=$(pwd)/libAppImageUpdaterBridge.so
```

## Update.py

```
#!/usr/bin/env python3
import os
import sys
from PyQt5.QtCore import QPluginLoader
from PyQt5.QtCore import QCoreApplication
if len(sys.argv) < 2:
print("Usage: ./Update.py [APPIMAGE PATH]")
sys.exit(0)
app = QCoreApplication(sys.argv)
# Try to load the plugin from predefined
# Qt Plugin paths.
loader = QPluginLoader()
loader.setFileName('libAppImageUpdaterBridge')
if not loader.load():
try:
plugin_path = os.eviron['PLUGIN_PATH']
except:
print("Unable to resolve plugin path.")
sys.exit(0)
loader.setFileName(plugin_path)
if not loader.load():
print("Cannot load plugin because: {}".format(loader.errorString()))
sys.exit(-1)
appimage_path = sys.argv[1]
obj = loader.instance()
def handleFinish(info, old_appimge_path):
print(info)
app.quit()
def handleError(code):
print("A error occured, error code: {}".format(code))
app.quit()
def handleUpdate(avail):
if avail:
print("A new version of the AppImage is available.")
print("Updating now... ")
obj.start()
else:
print("You have the latest AppImage!")
app.quit()
obj.updateAvailable.connect(handleUpdate)
obj.finished.connect(handleFinish)
obj.error.connect(handleError)
obj.setAppImage(appimage_path)
print("Checking for Update... ")
obj.checkForUpdate()
sys.exit(app.exec_())
```

## Execution

```
$ chmod +x Update.py
$ ./Update.py some.AppImage
```

See the examples directory in the source tree for more examples.
2 changes: 1 addition & 1 deletion docs/UsingPlugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ AppImage Updater Bridge can compiled as a **Qt Plugin**. When it is built as a Q

Qt plugins thus makes us to maintain a single code base instead of maintaining a lot of ports. This makes less bug in the code base and there is no time wasted in making bindings.

You can see the plugin interface here.
You can see the plugin interface [here](PluginInterface.html).

To read more about Qt plugins, Please refer the official documentation.

Expand Down
57 changes: 57 additions & 0 deletions examples/PyQt5Update/Update.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env python3
import os
import sys
from PyQt5.QtCore import QPluginLoader
from PyQt5.QtCore import QCoreApplication

if len(sys.argv) < 2:
print("Usage: ./Update.py [APPIMAGE PATH]")
sys.exit(0)

app = QCoreApplication(sys.argv)

# Try to load the plugin from predefined
# Qt Plugin paths.
loader = QPluginLoader()
loader.setFileName('libAppImageUpdaterBridge')
if not loader.load():
try:
plugin_path = os.eviron['PLUGIN_PATH']
except:
print("Unable to resolve plugin path.")
sys.exit(0)
loader.setFileName(plugin_path)
if not loader.load():
print("Cannot load plugin because: {}".format(loader.errorString()))
sys.exit(-1)


appimage_path = sys.argv[1]
obj = loader.instance()

def handleFinish(info, old_appimge_path):
print(info)
app.quit()

def handleError(code):
print("A error occured, error code: {}".format(code))
app.quit()

def handleUpdate(avail):
if avail:
print("A new version of the AppImage is available.")
print("Updating now... ")
obj.start()
else:
print("You have the latest AppImage!")
app.quit()

obj.updateAvailable.connect(handleUpdate)
obj.finished.connect(handleFinish)
obj.error.connect(handleError)

obj.setAppImage(appimage_path)

print("Checking for Update... ")
obj.checkForUpdate()
sys.exit(app.exec_())
1 change: 0 additions & 1 deletion include/appimageupdaterbridge_p.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ namespace AppImageUpdaterBridge {
void start();
void cancel();
void setAppImage(const QString&);
//void setAppImage(QFile*);
void setShowLog(bool);
void setOutputDirectory(const QString&);
void setProxy(const QNetworkProxy&);
Expand Down
Loading

0 comments on commit a04e07a

Please sign in to comment.