Flow.Launcher icon indicating copy to clipboard operation
Flow.Launcher copied to clipboard

Add JsonRPCPlugin.cs Rerun implementation

Open taooceros opened this issue 4 years ago • 21 comments

#635

taooceros avatar Aug 12 '21 04:08 taooceros

So excited to try this out! Is it ready for test? The build is failed :smile:

pc223 avatar Aug 13 '21 05:08 pc223

Yeah you can test it out. It is not a complex change so I believe my logic (haven't tested it out myself XD).

taooceros avatar Aug 13 '21 06:08 taooceros

I would like to implement this after #653, but currently it should work fine.

taooceros avatar Aug 13 '21 06:08 taooceros

Tested the RerunDelay seems work OK 👍

@Garulf yo check this out! Is this what you request? :smile:

Plugin code, generate random number, rerun every 200ms

import json
import sys


def main():
    request_data = sys.argv[1]
    request_dictionary = json.loads(request_data)
    if request_dictionary['method'] == 'query':
        import random
        response_dictionary = {
            'result': [
                {
                    "Title": f"{random.random()}",
                    "SubTitle": "This is my hello world",
                    "IconPath": "favicon.ico",
                    "JsonRPCAction": {
                        'method': 'Flow.Launcher.ShowApp',
                        'parameters': [],
                    },
                    
                },
            ],
            "RerunDelay":200,
        }


        response_converted_to_json_string = json.dumps(response_dictionary)
        print(response_converted_to_json_string)
    

if __name__ == '__main__':
    main()

pc223 avatar Aug 13 '21 06:08 pc223

Tested the RerunDelay seems work OK 👍

@Garulf yo check this out! Is this what you request? 😄

Plugin code, generate random number, rerun every 200ms

import json
import sys


def main():
    request_data = sys.argv[1]
    request_dictionary = json.loads(request_data)
    if request_dictionary['method'] == 'query':
        import random
        response_dictionary = {
            'result': [
                {
                    "Title": f"{random.random()}",
                    "SubTitle": "This is my hello world",
                    "IconPath": "favicon.ico",
                    "JsonRPCAction": {
                        'method': 'Flow.Launcher.ShowApp',
                        'parameters': [],
                    },
                    
                },
            ],
            "RerunDelay":200,
        }


        response_converted_to_json_string = json.dumps(response_dictionary)
        print(response_converted_to_json_string)
    

if __name__ == '__main__':
    main()

its... its beautiful!!! @taooceros you're awesome!

Going to try this out as soon as I can!

Garulf avatar Aug 13 '21 06:08 Garulf

Any chance to have the loading bar trigger while a rerun is scheduled? For example when polling a external web API you dont want to hit it too often. But it may be beneficial to indicate that Flow is still working.

Edit: Mouse is flashing between a loading indicator and normal cursor after using this method. Almost like the scheduled rerun hasnt been canceled.

Edit2: Yeah, log shows scheduled reruns are not halting after Flow's window closes. Flow is closed yet its still rerunning in the background.

Edit3: selection jumping to top on each rerun if you use arrow keys to select you're selection will keep jumping to the top of the list.

Garulf avatar Aug 13 '21 07:08 Garulf

Previously you couldn't see if your action went through, but now its immediately obvious if the toggle fails or not: Animation Very cool!

Garulf avatar Aug 13 '21 07:08 Garulf

Yeah we do, let me change a bit.

taooceros avatar Aug 13 '21 07:08 taooceros

@taooceros Quick consult, do you see this code have any obvious problem? This breaks after a merge this PR to my personal code (have customized debug logs). It breaks if I typing fast on a Python plugins. I'll make a detail bug report later if needed.

JsonRPCPlugin.cs:246

// Mutate intercept source

// Upstream `source`
// await using var source = process.StandardOutput.BaseStream;

await using var mySource = process.StandardOutput.BaseStream; 

var debugOuput = mySource.ReadToEnd();
Log.Debug($"|JsonRPCPlugin.ExecuteAsync|result:<{debugOuput}>");
var bytesOutput = Encoding.UTF8.GetBytes(debugOuput);

await using var source = new MemoryStream(bytesOutput);

pc223 avatar Aug 13 '21 07:08 pc223

@taooceros Quick consult, do you see this code have any obvious problem? This breaks after a merge this PR to my personal code (have customized debug logs). It breaks if I typing fast on a Python plugins. I'll make a detail bug report later if needed.

JsonRPCPlugin.cs:246

// Mutate intercept source

// Upstream `source`
// await using var source = process.StandardOutput.BaseStream;

await using var mySource = process.StandardOutput.BaseStream; 

var debugOuput = mySource.ReadToEnd();
Log.Debug($"|JsonRPCPlugin.ExecuteAsync|result:<{debugOuput}>");
var bytesOutput = Encoding.UTF8.GetBytes(debugOuput);

await using var source = new MemoryStream(bytesOutput);

Could you upload it as a branch in your fork, so I can see more code which leads to the problem.

taooceros avatar Aug 13 '21 07:08 taooceros

@taooceros Quick consult, do you see this code have any obvious problem? This breaks after a merge this PR to my personal code (have customized debug logs). It breaks if I typing fast on a Python plugins. I'll make a detail bug report later if needed.

JsonRPCPlugin.cs:246

// Mutate intercept source

// Upstream `source`
// await using var source = process.StandardOutput.BaseStream;

await using var mySource = process.StandardOutput.BaseStream; 

var debugOuput = mySource.ReadToEnd();
Log.Debug($"|JsonRPCPlugin.ExecuteAsync|result:<{debugOuput}>");
var bytesOutput = Encoding.UTF8.GetBytes(debugOuput);

await using var source = new MemoryStream(bytesOutput);

Oh probably if you type faster, the request will be canceled? So only the last one may be log.

taooceros avatar Aug 13 '21 07:08 taooceros

@taooceros Here is the code that breaks, it just for log out the RPC response of python plugin

https://github.com/pc223/Flow.Launcher/commit/1cef7722e500656f9a6ca212bddbb23df25402d5

These lines are the only different compare to this PR

// await using var source = process.StandardOutput.BaseStream;
await using var mySource = process.StandardOutput.BaseStream; 

var debugOuput = mySource.ReadToEnd();
Log.Debug($"|JsonRPCPlugin.ExecuteAsync|result:<{debugOuput}>");


var bytesOutput = Encoding.UTF8.GetBytes(debugOuput);

await using var source = new MemoryStream(bytesOutput);

pc223 avatar Aug 13 '21 08:08 pc223

Have you merged upstream/dev? You may need to fetch first. Or simply git pull upstream(or the remote pointing main repo) dev. There should be conflict between it.

taooceros avatar Aug 13 '21 08:08 taooceros

Have you merged upstream/dev? You may need to fetch first. Or simply git pull upstream(or the remote pointing main repo) dev. There should be conflict between it.

Check out https://github.com/pc223/Flow.Launcher/tree/JsonRPCRerun on my repo, I modified directly base on this PR

pc223 avatar Aug 13 '21 08:08 pc223

Getting errors with latest build: https://github.com/Flow-Launcher/Flow.Launcher/pull/648/commits/df62935d94d7c584b175eb296f96c263d01f0ab9

Please open new issue in: https://github.com/Flow-Launcher/Flow.Launcher/issues/new
1. upload log file: E:\Users\Garulf\Apps\FlowLauncher\app-1.8.2\UserData\Logs\1.8.2\2021-08-13.txt
2. copy below exception message

Flow Launcher version: 1.8.2
OS Version: Microsoft Windows NT 10.0.19043.0
IntPtr Length: 8
x64: True

Python Path: E:\Users\Garulf\Apps\FlowLauncher\app-1.8.2\UserData\PythonEmbeddable\pythonw.exe
Date: 08/13/2021 05:17:07
Exception:
System.IO.InvalidDataException: HA-Commander|Traceback (most recent call last):
  File "E:\Users\Garulf\Apps\FlowLauncher\app-1.8.2\UserData\Plugins\HA-Commander\main.py", line 13, in <module>
    Commander()
  File "E:\Users\Garulf\Apps\FlowLauncher\app-1.8.2\UserData\Plugins\HA-Commander\plugin\main.py", line 34, in __init__
    super().__init__()
  File "E:\Users\Garulf\Apps\FlowLauncher\app-1.8.2\UserData\Plugins\HA-Commander\lib\flox\flox.py", line 84, in __init__
    super().__init__()
  File "E:\Users\Garulf\Apps\FlowLauncher\app-1.8.2\UserData\Plugins\HA-Commander\lib\flox\launcher.py", line 26, in __init__
    request_method = dict(methods)[request_method_name]
KeyError: 'query_rerun'

   at Flow.Launcher.Core.Plugin.JsonRPCPlugin.ExecuteAsync(ProcessStartInfo startInfo, CancellationToken token) in C:\projects\flow-launcher\Flow.Launcher.Core\Plugin\JsonRPCPlugin.cs:line 254
   at Flow.Launcher.Core.Plugin.JsonRPCPlugin.ExecuteAsync(ProcessStartInfo startInfo, CancellationToken token) in C:\projects\flow-launcher\Flow.Launcher.Core\Plugin\JsonRPCPlugin.cs:line 268
   at Flow.Launcher.Core.Plugin.JsonRPCPlugin.<>c__DisplayClass18_0.<<QueryAsync>g__TryRerun|0>d.MoveNext() in C:\projects\flow-launcher\Flow.Launcher.Core\Plugin\JsonRPCPlugin.cs:line 297
--- End of stack trace from previous location ---
   at Flow.Launcher.Core.Plugin.JsonRPCPlugin.QueryAsync(Query query, CancellationToken token) in C:\projects\flow-launcher\Flow.Launcher.Core\Plugin\JsonRPCPlugin.cs:line 281
   at Flow.Launcher.Core.Plugin.JsonRPCPlugin.QueryAsync(Query query, CancellationToken token) in C:\projects\flow-launcher\Flow.Launcher.Core\Plugin\JsonRPCPlugin.cs:line 282
   at Flow.Launcher.Core.Plugin.PluginManager.<>c__DisplayClass22_0.<<QueryForPluginAsync>b__0>d.MoveNext() in C:\projects\flow-launcher\Flow.Launcher.Core\Plugin\PluginManager.cs:line 192
--- End of stack trace from previous location ---
   at Flow.Launcher.Infrastructure.Stopwatch.DebugAsync(String message, Func`1 action) in C:\projects\flow-launcher\Flow.Launcher.Infrastructure\Stopwatch.cs:line 34
   at Flow.Launcher.Core.Plugin.PluginManager.QueryForPluginAsync(PluginPair pair, Query query, CancellationToken token) in C:\projects\flow-launcher\Flow.Launcher.Core\Plugin\PluginManager.cs:line 191
   at Flow.Launcher.ViewModel.MainViewModel.<>c__DisplayClass111_0.<<QueryResults>g__QueryTask|2>d.MoveNext() in C:\projects\flow-launcher\Flow.Launcher\ViewModel\MainViewModel.cs:line 553
--- End of stack trace from previous location ---
   at Flow.Launcher.ViewModel.MainViewModel.QueryResults() in C:\projects\flow-launcher\Flow.Launcher\ViewModel\MainViewModel.cs:line 527
   at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__140_0(Object state)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)

Garulf avatar Aug 13 '21 09:08 Garulf

Yeah I change the method of query rerun to "query_rerun" to indicate it is a rerun. Forget to do that in last build.

taooceros avatar Aug 13 '21 09:08 taooceros

Yeah I change the method of query rerun to "query_rerun" to indicate it is a rerun. Forget to do that in last build.

Ah! I see.

Garulf avatar Aug 13 '21 09:08 Garulf

Seems Esc or change focus does not stop the rerun, maybe the token is not canceled?

pc223 avatar Aug 13 '21 11:08 pc223

Yeah that's true.

taooceros avatar Aug 13 '21 11:08 taooceros

Have you merged upstream/dev? You may need to fetch first. Or simply git pull upstream(or the remote pointing main repo) dev. There should be conflict between it.

Check out https://github.com/pc223/Flow.Launcher/tree/JsonRPCRerun on my repo, I modified directly base on this PR

Probably it doesn't work because you didn't seek to origin, so the getbytes is creating nothing. You can do it like this.

                try
                {
                    // token expire won't instantly trigger the exception, 
                    // manually kill process at before
                    await source.CopyToAsync(buffer, token);
                }
                catch (OperationCanceledException)
                {
                    await buffer.DisposeAsync();
                    return Stream.Null;
                }
+              buffer.Seek(0, SeekOrigin.Begin);
+              var debugOuput = await new StreamReader(buffer).ReadToEndAsync();
+
+              Log.Debug($"|JsonRPCPlugin.ExecuteAsync|result:<{debugOuput}>");

taooceros avatar Aug 13 '21 22:08 taooceros

It is also possible that the process is killed so the stream won't read anything

taooceros avatar Aug 13 '21 22:08 taooceros