Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added new resource file system #397

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

PabloOQ
Copy link
Collaborator

@PabloOQ PabloOQ commented Nov 15, 2024

So, I was going to do a Privacy redirector module as per #7. But I noticed all the logic to download files is in ClearUrlCatalog.java, to avoid code duplication I got sidetracked working on this.
This is the, 4th(? or 3rd, I don't remember) iteration, but the code is still untested, I don't want to spend more time than necessary in something that might not be merged, althought it should work as it is mainly refactoring.

Here is the class diagram to make things clearer at a glance. I have omitted certain things so it is easier to follow
The main thing to worry is the diagonal of abstract classes as each relies on the previous.

classDiagram
    class ResourceContextInterface{
        <<interface>>
        +getContext() Activity
    }

    class ResourceGuideInterface~T~{
        <<interface>>
        +toObject(String content) T
        +toObjectThrows(String content) T
        +toString(T) String
        +getEmpty() T
    }
    ResourceGuideInterface~T~ <|-- ResourceGuide~T~
    ResourceGuideInterface~T~ <|-- BuiltInResource~T~ : Delegates to previous
    ResourceGuideInterface~T~ <|-- ModifiableResource~T~ : Delegates to previous
   
    class ResourceGuide~T~{
        <<abstract>>
        +toObject(String content) T
        +toObjectThrows(String content) T*
        +toString(T) String*
        +getEmpty() T*
    }

    ResourceGuide~JSONObject~ <|-- JsonGuide : JSONObject
    class JsonGuide{
        + toObjectThrows(String content) JSONObject
        + toString(JSONObject content) String
        + getEmpty() JSONObject
    }

    ResourceGuide~T~ o-- BuiltInResource~T~ 
    class BuiltInResource~T~{
        <<abstract>>
        + getBuiltIn() T
        # buildBuiltIn() T*
    }

    BuiltInResource~T~ <|-- BuiltInResourceFile~T~ 
    class BuiltInResourceFile~T~{
        # buildBuiltIn() T
    }

    BuiltInResource~T~ o-- ModifiableResource~T~
    class ModifiableResource~T~{
        <<abstract>>
        + getCatalog() T
        + clear ()
    }

    ModifiableResource~T~ <|-- ManualEditResource~T~
    class ManualEditResource~T~{
        + save()
    }

    ModifiableResource~T~ <|-- UpdateableResource~T~
    class UpdateableResource~T~{
        + _update(boolean background)
    }
    
    UpdateableResource~T~ <|-- AutoUpdateableResource~T~
    class AutoUpdateableResource~T~{
        + updateIfNecessary()
    }

Loading

Here is an example to show the actual use.

  1. Create a guide to the extension, used for transforming to string/object (this way we can support other fomats like xml)
  2. Create a builtin source, either a read only file (from the assets folder) or dynamically built, like the patterns checker module
  3. The way this resource will be modified, either manually by the user or it updates from the internet, which can be automatic.
Activity context = null;
// ClearUrls like example
// first, the extension
var type = new JsonGuide();
// second, the builtin source, in this case a file
BuiltInResource<JSONObject> fallback = new BuiltInResourceFile<>(
        context, type, "built-in.json");
// third, how the resource will be modified, in this case it auto downloads
ModifiableResource<JSONObject> modifiable = new AutoUpdateableResource<>(
        fallback, "auto-example.json",
        "example-module",
        "http://fake.domain/catalog",
        "http://fake.domain/hash",
        /*built-in.json-timestamp*/777L/*built-in.json-timestamp*/,
        JavaUtils.weeksToMillis(1));


// Pattern url like example
// first, the extension
type = new JsonGuide();
// second, the builtin source, in this case dynamically built
fallback = new BuiltInResource<>(
        context, type) {
    @Override
    protected JSONObject buildBuiltIn() throws Exception {
        return new JSONObject()

                // built from the translated strings
                .put(context.getString(R.string.mPttrn_ascii), new JSONObject()
                        .put("regex", "[^\\p{ASCII}]")
                )
                .put(context.getString(R.string.mPttrn_http), new JSONObject()
                        .put("regex", "^http://")
                        .put("replacement", "https://")
                )
                ;
    }
};
// third, how the resource will be modified, in this case, manual edit
modifiable = new ManualEditResource<>(
        fallback,"manual-example.json");

If you like this change, let me know and I will keep working on the things that will need to be done in order for this to work:

  • Change all current implementations of retrieving data from resources, which . Doesn't need to be done all at the same time.
    • JsonCatalog hopefully (only requires changing one variable, hopefully)
      • AutomationRules
      • HostCatalogs
      • PatternCatalog
    • ClearUrlCatalog
  • Add an auto migration system (sidetracking again!)
    • Only affects the ClearURLs module, as it stores in the same file both, the updateable catalog and the rules made by the user. The new resource system forces both to be different files.

Let me know what you think! And don't worry if you feel like all this should be scrapped, it is a huge change. Take all the time you need I don't want to put any pressure on you, even if that means waiting for other PRs that are currently open.

@github-actions github-actions bot added the Core Change the core code label Nov 15, 2024
Copy link
Contributor

This PR builds correctly, here is the generated apk.
This unsigned version can be installed alongside the original app and should only be used for testing the changes, not for daily usage.

Download testing apk

You must be logged in for the link to work.
The link will expire in 14 days, at Fri Nov 29 13:42:57 UTC 2024.


This is an automatic comment created by a Github Action

@@ -0,0 +1,71 @@
package com.trianguloy.urlchecker.modules.companions.ResourceCatalogs;

Check warning

Code scanning / Pmd (reported by Codacy)

Package name contains upper case characters Warning

Package name contains upper case characters
@@ -0,0 +1,65 @@
package com.trianguloy.urlchecker.modules.companions.ResourceCatalogs;

Check warning

Code scanning / Pmd (reported by Codacy)

Package name contains upper case characters Warning

Package name contains upper case characters
@@ -0,0 +1,24 @@
package com.trianguloy.urlchecker.modules.companions.ResourceCatalogs;

Check warning

Code scanning / Pmd (reported by Codacy)

Package name contains upper case characters Warning

Package name contains upper case characters
@@ -0,0 +1,25 @@
package com.trianguloy.urlchecker.modules.companions.ResourceCatalogs;

Check warning

Code scanning / Pmd (reported by Codacy)

Package name contains upper case characters Warning

Package name contains upper case characters
@@ -0,0 +1,23 @@
package com.trianguloy.urlchecker.modules.companions.ResourceCatalogs;

Check warning

Code scanning / Pmd (reported by Codacy)

Package name contains upper case characters Warning

Package name contains upper case characters
// ------------------- ui -------------------

Button updateButton;
TextView txt_check;

Check warning

Code scanning / Pmd (reported by Codacy)

Fields should be declared at the top of the class, before any method declarations, constructors, initializers or inner classes. Warning

Fields should be declared at the top of the class, before any method declarations, constructors, initializers or inner classes.

Button updateButton;
TextView txt_check;
TextView txt_update;

Check warning

Code scanning / Pmd (reported by Codacy)

Fields should be declared at the top of the class, before any method declarations, constructors, initializers or inner classes. Warning

Fields should be declared at the top of the class, before any method declarations, constructors, initializers or inner classes.
super.clear();
}

public void _update(boolean background) {

Check warning

Code scanning / Pmd (reported by Codacy)

The instance method name '_update' doesn't match '[a-z][a-zA-Z0-9]*' Warning

The instance method name '_update' doesn't match '[a-z][a-zA-Z0-9]*'
* Network operation, designed to be run in a background thread.
* Returns the message to display to the user about the result
*/
protected UpdateResult _updateResource() {

Check warning

Code scanning / Pmd (reported by Codacy)

The instance method name '_updateResource' doesn't match '[a-z][a-zA-Z0-9]*' Warning

The instance method name '_updateResource' doesn't match '[a-z][a-zA-Z0-9]*'
/**
* Saves a new local file. Returns if it was up to date, updated or an error happened.
*/
private UpdateResult _save(String rawContent) {

Check warning

Code scanning / Pmd (reported by Codacy)

The instance method name '_save' doesn't match '[a-z][a-zA-Z0-9]*' Warning

The instance method name '_save' doesn't match '[a-z][a-zA-Z0-9]*'
@TrianguloY
Copy link
Owner

Let's see,

It's true I would like to extract the logic for the 'automatic update of a file-like asset', as that will be needed in other modules (even now it will help with the current ones, as you mentioned in the description)

My main concern is that the pr is...big. Not by a lot, I've seen bigger, but still I wonder if all the logic and classes are needed. Maybe they are, but I still need to review everything, and right now I simply can't :(

So, for now I think it's best to leave this. But don't delete it! If I come back to this feature I'll definitely take a look at this and try to adapt it. Thank you for your effort, much appreciated!

Alternatively, maybe what you can try to do (if you want) is to extract the current logic. Just a cut/paste of code, moving things from a file to another, and only adding minimal 'glue logic' when needed. That could help with a later refactor, but since this code is a bit 'entangled' with other things, I don't think it will be easy either...

@PabloOQ
Copy link
Collaborator Author

PabloOQ commented Nov 19, 2024

but still I wonder if all the logic and classes are needed. Maybe they are

All the logic is needed, I think, however, the classes, well that is up for debate. Because the objective was to remove duplicated code, I tried to (strictly) make the responsibilites not interfere with each other, and that led to this. I might have overused the interfaces, and I don't think we will ever need non-json files.

Alternatively, maybe what you can try to do (if you want) is to extract the current logic. Just a cut/paste of code, moving things from a file to another, and only adding minimal 'glue logic' when needed. That could help with a later refactor, but since this code is a bit 'entangled' with other things, I don't think it will be easy either...

That's the thing, I didn't write much code for this PR. The code for the methods is copied from other places in the source code, and the variables are too, maybe with different names. I avoided refactoring directly so involved classes could work correctly until they were explicitly moved to the new system.

What if I do it like this?

  1. Add a substantial amount of comments to each method that directly references the exact origin of that specific code. I was thinking of using the javadoc @implSpec annotation, temporarily, until this is finished. This should hopefully make reviewing way easier.
  2. Implement the Privacy Redirector Module as an example of use. That way I can also test if everything works correctly, after all, I need a file to test if the file system works. Although that would mean 2 features in 1 PR, which I don't like.
  3. No more changes. Because I did not refactor the original classes, but instead copy/pasted, they will keep working correctly. No changes to ANY of these, and no migration either ↓
  • Change all current implementations of retrieving data from resources, which . Doesn't need to be done all at the same time.
    • JsonCatalog hopefully (only requires changing one variable, hopefully)
      • AutomationRules
      • HostCatalogs
      • PatternCatalog
    • ClearUrlCatalog
  1. Later, when you have the time, or the code is needed, it will be ready for review and merge. You could completely ignore the Privacy Redirector Module and disable or remove it entirely if necessary, to avoid reviewing and even bigger PR.
  2. Remove the comments from the @implSpec annotation.
  3. If everything works correctly, slowly do what was left behind on point 3.

I honestly don't mind having the PR open, if you don't mind either, and if this is something that at some point in the future will need to be revisited, then I don't see any problem on finishing this now, and leaving it open until review.

If you are ok with this let me know and I will keep working on it.


Btw, off-topic, I have a small patch for the automations, it allows for both Strings or arrays of strings in the "regex" field. I felt I was cluttering the file with too many "Unshort X shortener service" and thought it might be useful. I know that technically I can make a regex that supports everything, but this is more accessible and easier to maintain in my opinion. If the decision to have only Strings wasn't made on purpose, do you want me to make a PR on this?

@TrianguloY
Copy link
Owner

I honestly don't mind having the PR open

Me neither! so let's keep it for revisiting later when possible.

If you are ok with this let me know and I will keep working on it.

That's up to you, as I said I do want to extract the functionality, but you already know me, I prefer small prs...but I'm aware it may be impossible in this case. Your 6-steps process looks good for me, although maybe instead of a comment for each code piece you can add a single one at the class (at least when everything in a class comes from a single source)


Btw, off-topic, I have a small patch for the automations, it allows for both Strings or arrays of strings in the "regex" field

Like the patterns module? where you can either specify "regex": "something" or "regex": ["something", "something else"]?
If so, please do! Should be short, and definitely useful, I should be able to quickly merge it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Core Change the core code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants