I am trying to monitor the ~/.local directory according to the Vala documentation I can monitor the home correctly. but I can't monitor the the ~/.local.
initFileMonitor V1:
public void initFileMonitor(){
try {
string homePath = Environment.get_home_dir();
string filePath = homePath + "/.local";
File file = File.new_for_path(filePath);
FileMonitor monitor = file.monitor_directory(FileMonitorFlags.NONE, null);
print ("\nMonitoring: %s\n", file.get_path ());
monitor.changed.connect ((src, dest, event) => {
if (dest != null) {
print ("%s: %s, %s\n", event.to_string (), src.get_path (), dest.get_path ());
} else {
print ("%s: %s\n", event.to_string (), src.get_path ());
}
});
} catch (Error err) {
print ("Error: %s\n", err.message);
}
}
terminal output(no error, no monitoring):
Monitoring: /home/srdr/.local
Because the file monitor is stored in a local variable it is like other variables destroyed (or in GObject terms finalised/destructed) at the end of the function call
To ensure it lives long enough you should make it a field on a class, then the FileMonitor instance is 'owned' by an instance of that class rather than each call to a specific method
Runnable demo (valac demo.vala --pkg gio-2.0)
class FileMonitorDemo {
private FileMonitor monitor;
public void initFileMonitor() {
var path = Path.build_filename(Environment.get_home_dir(), ".local");
var file = File.new_for_path(path);
try {
monitor = file.monitor_directory(NONE);
message ("Monitoring: %s", file.get_path ());
monitor.changed.connect ((src, dest, event) => {
if (dest != null) {
print ("%s: %s, %s\n", event.to_string (), src.get_path (), dest.get_path ());
} else {
print ("%s: %s\n", event.to_string (), src.get_path ());
}
});
} catch (Error err) {
critical ("Error: %s\n", err.message);
}
}
}
void main () {
var filemon = new FileMonitorDemo();
filemon.initFileMonitor();
new MainLoop ().run ();
}
You need to actually run the monitor by creating a main loop and having it wait for events:
new MainLoop ().run ();
Related
I have Java CLI application based on cliche library and I want to migrate it to picocli.
My application was based on cliche so I have a lot of methods with asg.cliche.Command annotation which return some result. cliche prints command methods's result automatically so result was printed in command line. I replaced asg.cliche.Command annotations by picocli.CommandLine.Command and I see that picocli does not print command methods's results.
I have following class:
import picocli.CommandLine;
#CommandLine.Command(subcommandsRepeatable = true)
public class Foo
{
public static void main( String[] args )
{
new CommandLine( new Foo() ).execute( args );
}
#CommandLine.Command
public String sayHello()
{
return "Hello";
}
#CommandLine.Command
public String sayGoodbye()
{
return "GoodBye";
}
}
when I call java -cp myJar.jar Foo sayHello sayGoodbye I do not see any output.
I see three solutions:
1. Modify each methods to print result instead of return it.
import picocli.CommandLine;
#CommandLine.Command( subcommandsRepeatable = true )
public class Foo2
{
public static void main( String[] args )
{
new CommandLine( new Foo2() ).execute( args );
}
#CommandLine.Command
public void sayHello()
{
System.out.println( "Hello" );
}
#CommandLine.Command
public void sayGoodbye()
{
System.out.println( "GoodBye" );
}
}
I am not happy with this solution. I prefer not modify my methods.
Retrieve results after execution.
public static void main( String[] args )
{
final CommandLine commandLine = new CommandLine( new Foo() );
commandLine.execute( args );
CommandLine.ParseResult parseResult = commandLine.getParseResult();
for( CommandLine.ParseResult pr : parseResult.subcommands() )
{
System.out.println( pr.commandSpec().commandLine()
.getExecutionResult()
.toString() );
}
}
I see a few problems with this solution. The main problem is formatting. Execution result can be null, array, collection. The second problem is that results are printed after execution of all subcommands. If second subcommand throws exception then I firstly see exception stack trace and after that I see result of first subcommand.
Ask on stackoverflow if there is some better solution. I do not believe that there is no any configuration option in picocli which enable results printing.
Personally, I like your first solution best, it is simple and easy to maintain. Maybe introduce a helper method for the printing and formatting so the command methods can look like this:
#CommandLine.Command
public String sayGoodbye()
{
return printValue("GoodBye");
}
You already found the CommandLine.getParseResult method; perhaps a helper method could assist with the formatting there as well.
There is a third option, but it is unfortunately quite a bit more complex: you can create a custom IExecutionStrategy that prints the result of each command after executing it. It involves copying a lot of code from the picocli internals and it’s not really a realistic solution; I just mention it for completeness.
// extend RunLast to handle requests for help/version and exit code stuff
class PrintingExecutionStrategy extends CommandLine.RunLast {
#Override
protected List<Object> handle(ParseResult parseResult) throws ExecutionException {
// Simplified: executes only the last subcommand (so no repeating subcommands).
// Look at RunLast.executeUserObjectOfLastSubcommandWithSameParent if you need repeating subcommands.
List<CommandLine> parsedCommands = parseResult.asCommandLineList();
CommandLine last = parsedCommands.get(parsedCommands.size() - 1);
return execute(last, new ArrayList<Object>());
}
// copied from CommandLine.executeUserObject,
// modified to print the execution result
private List<Object> execute(CommandLine cmd, List<Object> executionResultList) throws Exception {
Object command = parsed.getCommand();
if (command instanceof Runnable) {
try {
((Runnable) command).run();
parsed.setExecutionResult(null); // 4.0
executionResultList.add(null); // for compatibility with picocli 2.x
return executionResultList;
} catch (ParameterException ex) {
throw ex;
} catch (ExecutionException ex) {
throw ex;
} catch (Exception ex) {
throw new ExecutionException(parsed, "Error while running command (" + command + "): " + ex, ex);
}
} else if (command instanceof Callable) {
try {
#SuppressWarnings("unchecked") Callable<Object> callable = (Callable<Object>) command;
Object executionResult = callable.call();
System.out.println(executionResult); <-------- print result
parsed.setExecutionResult(executionResult);
executionResultList.add(executionResult);
return executionResultList;
} catch (ParameterException ex) {
throw ex;
} catch (ExecutionException ex) {
throw ex;
} catch (Exception ex) {
throw new ExecutionException(parsed, "Error while calling command (" + command + "): " + ex, ex);
}
} else if (command instanceof Method) {
try {
Method method = (Method) command;
Object[] parsedArgs = parsed.getCommandSpec().argValues();
Object executionResult;
if (Modifier.isStatic(method.getModifiers())) {
executionResult = method.invoke(null, parsedArgs); // invoke static method
} else if (parsed.getCommandSpec().parent() != null) {
executionResult = method.invoke(parsed.getCommandSpec().parent().userObject(), parsedArgs);
} else {
executionResult = method.invoke(parsed.factory.create(method.getDeclaringClass()), parsedArgs);
}
System.out.println(executionResult); <-------- print result
parsed.setExecutionResult(executionResult);
executionResultList.add(executionResult);
return executionResultList;
} catch (InvocationTargetException ex) {
Throwable t = ex.getTargetException();
if (t instanceof ParameterException) {
throw (ParameterException) t;
} else if (t instanceof ExecutionException) {
throw (ExecutionException) t;
} else {
throw new ExecutionException(parsed, "Error while calling command (" + command + "): " + t, t);
}
} catch (Exception ex) {
throw new ExecutionException(parsed, "Unhandled error while calling command (" + command + "): " + ex, ex);
}
}
throw new ExecutionException(parsed, "Parsed command (" + command + ") is not a Method, Runnable or Callable");
}
}
Use it like this:
public static void main(String... args) {
new CommandLine(new Foo())
.setExecutionStrategy(new PrintingExecutionStrategy())
.execute(args);
}
I wouldn’t recommend the above.
Update: I thought of another, fourth, option (actually a variation of your 2nd solution). You can specify a custom IExecutionExceptionHandler that doesn’t print the stacktrace, but instead stores the exception so you can print the stacktrace after printing the command results. Something like this:
class MyHandler extends IExecutionExceptionHandler() {
Exception exception;
public int handleExecutionException(Exception ex,
CommandLine commandLine,
ParseResult parseResult) {
//ex.printStackTrace(); // no stack trace
exception = ex;
}
}
Use it like this:
public static void main(String... args) {
MyHandler handler = new MyHandler();
CommandLine cmd = new CommandLine(new Foo())
.setExecutionExceptionHandler(handler);
cmd.execute(args);
ParseResult parseResult = cmd.getParseResult();
for( ParseResult pr : parseResult.subcommands() )
{
System.out.println( pr.commandSpec().commandLine()
.getExecutionResult()
.toString() );
}
if (handler.exception != null) {
handler.exception.printStackTrace();
}
}
I am using FirebaseFunctions as well as https://github.com/voltrue2/in-app-purchase to validate purchases. I am having trouble sending the data back to my client. In the logs of my functions everything goes well and I get the result I want, but as I understand you have to return a promise in order to get the data back to the client when using Firebase's onCall https trigger. The code for my oncall trigger is here.
var iap = require('in-app-purchase');
var purchaseData;
const receipt = data;
iap.config({
googlePublicKeyPath: 'acualpublickey' ,
googleAccToken: 'actualtoken',
googleRefToken: 'actualtoken',
googleClientID: 'actualID',
googleClientSecret: 'actual seceret',
});
iap.setup()
.then(() => {
console.log("receipt: ", receipt)
return iap.validate(receipt).then(onSuccess).catch(onError);
}).catch((error) => {
console.log("error setup: " + error);
throw error;
});
function onSuccess(validatedData) {
var options = {
ignoreExpired: true // purchaseData will NOT contain exipired subscription items
};
purchaseData = iap.getPurchaseData(validatedData, options);
console.log("PurchseData : ", purchaseData);
console.log("ValidatedData : ", validatedData);
return purchaseData;
}
function onError(error) {
console.log("error onError: " + error);
throw error;
}
the function it is called on to be used is this one
void receiptJSONvalidation(String receipt){
if (receipt != null) {
try {
JSONObject jsonObject = new JSONObject(receipt);
Task<Object> validatedReceipt = validation(jsonObject);
validatedReceipt.addOnCompleteListener(this, new OnCompleteListener<Object>() {
#Override
public void onComplete(#NonNull Task<Object> task) {
if (!task.isSuccessful()) {
Exception e = task.getException();
if (e instanceof FirebaseFunctionsException) {
FirebaseFunctionsException ffe = (FirebaseFunctionsException) e;
FirebaseFunctionsException.Code code = ffe.getCode();
Object details = ffe.getDetails();
errorAlert("task unsuccessful: " + details.toString());
} else {
errorAlert("Error onComplete: " + e.getLocalizedMessage());
}
// ...
} else{
Gson gson = new Gson();
String taskResult = gson.toJson(task.getResult());
errorAlert("taskResult: " + taskResult);
}
}
});
} catch (JSONException e) {
errorAlert("Error Json: " + e.getLocalizedMessage());
}
} else {
errorAlert("You are not subscribed. Please purchase a subscription.");
}
}
the validation method is this
private Task<Object> validation(JSONObject receipt){
mFunctions = FirebaseFunctions.getInstance();
return mFunctions.getHttpsCallable("receiptValidation").call(receipt)
.continueWith(new Continuation<HttpsCallableResult,Object>() {
public Object then(#NonNull Task<HttpsCallableResult> task) throws Exception {
// This continuation runs on either success or failure, but if the task
// has failed then getResult() will throw an Exception which will be
// propagated down.
Object result = task.getResult().getData();
return result;
}
});
}
When I get to both taskResult and result I am getting null while my logs have the actual data I need. I tried to follow the documentation for these functions yet I still don't get what is needed. Also there seems to be a problem with my app not allowing the firebase function to finish. Sometimes the result pops up null before the function is even over. The function will say it took about 8 sec. Yet the alert pops up in way less time.
Is there a more sane way to program the following super simple set/get/close test program? Note that I had to duplicate the Redis close code and include it in both the set error path and in the get complete path.
import io.vertx.core.Vertx;
import io.vertx.redis.RedisClient;
import io.vertx.redis.RedisOptions;
public class RedisTest {
public static void main(String[] args) throws Exception {
Vertx vertx = Vertx.vertx();
String host = "localhost";
final RedisClient client = RedisClient.create(vertx,
new RedisOptions().setHost(host));
client.set("key", "value", r -> {
if (r.succeeded()) {
System.out.println("key stored");
client.get("key", s -> {
if (s.succeeded()) {
System.out.println("Retrieved value: " + s.result());
} else {
System.out.println("Connection or Operation Failed " + s.cause());
}
System.out.println("Closing Redis connection");
client.close(t -> {
if (s.succeeded()) {
System.out.println("Redis closed successfully.");
} else {
System.out.println("Connection or Operation Failed " + t.cause());
}
System.out.println("Closing vertx");
vertx.close();
});
});
} else {
System.out.println("Connection or Operation Failed " + r.cause());
System.out.println("Closing Redis connection");
client.close(s -> {
if (s.succeeded()) {
System.out.println("Redis closed successfully.");
} else {
System.out.println("Connection or Operation Failed " + s.cause());
}
System.out.println("Closing vertx");
vertx.close();
});
}
});
System.out.println("Exiting main");
}
}
I recommend see reactive api io.vertx.rxjava.redis.RedisClient. It's excellent(its main purposes) for the chained computation.
For example(I'm not tested this code):
client.rxSet("key", "value")
.flatMap(r -> client.rxGet("key"))
//calls on error or success
.doAfterTerminate(() -> {
client.rxClose();
vertx.close();
})
.subscribe(
success -> System.out.println("Chain completed"),
//all errors will be there
error -> System.out.println(error.getMessage())
);
I need to delete files from the cache of APT and with the functions of files that Vala provides not let me.
Someone who can give me a hand?
The code is the following:
//Compile it using: valac --pkg gtk+-3.0 --pkg glib-2.0 --pkg gio-2.0 del-apt-cache.vala
using Gtk;
using GLib;
private int64[] get_info_and_clean (File file, string space = "", Cancellable? cancellable = null) throws Error
{
int64 files = 0;
int64 size = 0;
int64[] data = new int64[2];
Array<string> paths = new Array<string> ();
FileInfo info = null;
FileEnumerator enumerator;
try {//This Try/Catch is to ignore the permissions of '/var/cache/apt/archives/partial'
enumerator = file.enumerate_children (
"standard::*",
FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
cancellable);
} catch (IOError e) {
stderr.printf ("WARNING: Unable to get size of dir '%s': %s\n", file.get_path (), e.message);
data[0] = 0;
data[1] = 0;
return data;
}
while (cancellable.is_cancelled () == false && ((info = enumerator.next_file (cancellable)) != null)) {
if (info.get_file_type () == FileType.DIRECTORY) {
File subdir = file.resolve_relative_path (info.get_name ());
get_info_and_clean (subdir, space + " ", cancellable);
} else {
files += 1;//Sum Files
size += info.get_size ();//Accumulates Size
paths.append_val (file.get_uri () + "/" + info.get_name ());
}
}
if (cancellable.is_cancelled ()) {
throw new IOError.CANCELLED ("Operation was cancelled");
}
data[0] = files;
data[1] = size;
File apt_file;
for (int i = 0; i < paths.length; i++) {
apt_file = File.new_for_uri (paths.index (i));
stdout.printf ("FILE: %s", paths.index (i));
try {
apt_file.delete ();
stdout.printf (" [DELETED]\n");
} catch (Error e) {
stdout.printf (" [ERROR: %s]\n\n", e.message);
}
}
stdout.printf ("APT CACHE FILES: %s\n", files.to_string());
stdout.printf ("APT CACHE SIZE: %s\n", size.to_string());
return data;
}
public static int main (string[] args) {
Gtk.init (ref args);
File APT_CACHE_PATH = File.new_for_path ("/var/cache/apt/archives");
try {
get_info_and_clean (APT_CACHE_PATH, "", new Cancellable ());
} catch (Error e) {
stdout.printf ("ERROR: %s\n", e.message);
}
Gtk.main ();
return 0;
}
When I run the program, I get the following error:
FILE: file:///var/cache/apt/archives/libdbus-1-3_1.10.6-1ubuntu3_amd64.deb [ERROR: Failed to delete file: Permission denied]
There's nothing Vala can do if the operating system is denying you permission. You need to run your Vala program as root either using sudo or setting the “setuid” bit on the application and changing the owner to root.
I am receiving an odd error with my scanner integration. I am making use of an OPOS scanner in my program. When the program closes I disable, release and close the device, but no other application can use it after my program runs. Also if I restart no application can use it. Not even my application which causes the issue. I did find that if I do not claim the device the issue doesn't happen. I am currently trying to get a fresh copy of the DLL in case the release method is somehow corrupted? Any other ideas?
public bool InitBarcode(bool overrideLGBarcode)
{
Util.LogMessage("Initializing barcode scanner!");
if (_barcodeScanner == null)
{
Util.LogMessage("Barcode scanner was null. instantiating a new one");
_barcodeScanner = new OPOSScanner();
_barcodeScanner.AutoDisable = true;
_barcodeScanner.DataEvent += BarcodeDataEventHandler;
Util.LogMessage("Added event handler");
}
else
{
Util.LogMessage("Barcode scanner was not null");
}
if (_barcodeScanner.Open("STI_USBSCANNER") != 0)
{
Util.LogMessage("Barcode scanner \"STI_USBSCANNER\" could not be opened!");
return false;
}
else
{
Util.LogMessage("STI_USBSCANNER was opened");
}
int result = _barcodeScanner.ClaimDevice(-1);
Util.LogMessage("Claiming barcode scanner returned result: " + result);
_barcodeScanner.DecodeData = true;
_barcodeScanner.DeviceEnabled = true;
_barcodeScanner.DataEventEnabled = true;
return true;
}
public void CloseBarcode()
{
Util.LogMessage("Disabling, Releasing and Closing the barcode scanner!");
_barcodeScanner.DataEvent -= BarcodeDataEventHandler;
Util.LogMessage("Removed event handler");
_barcodeScanner.AutoDisable = false;
_barcodeScanner.DecodeData = false;
_barcodeScanner.DataEventEnabled = false;
_barcodeScanner.DeviceEnabled = false;
if (_barcodeScanner.DeviceEnabled != false)
{
Util.LogMessage("Barcode scanner could not be disabled!");
}
else
{
Util.LogMessage("Barcode scanner was disabled!");
}
int result = _barcodeScanner.ReleaseDevice();
Util.LogMessage("ReleseDevice() yielded result of: " + result);
if (result != 0)
{
Util.LogMessage("Barcode scanner could not be released!");
}
else
{
Util.LogMessage("Barcode scanner was released!");
}
if (_barcodeScanner.Close() != 0)
{
Util.LogMessage("Barcode scanner could not be closed!");
}
else
{
Util.LogMessage("Barcode scanner was closed!");
}
_barcodeScanner = null;
}