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

readOnly properties cannot be internally updated? #333

Closed
erceguder opened this issue Sep 23, 2020 · 46 comments · Fixed by #335
Closed

readOnly properties cannot be internally updated? #333

erceguder opened this issue Sep 23, 2020 · 46 comments · Fixed by #335

Comments

@erceguder
Copy link

Latest release does not allow readOnly properties to be updated within the thing itself, e.g. examples/scripts/counter.js crashes on this line.

@danielpeintner
Copy link
Member

I believe this is a bug in the script and not in the node-wot implementation. We also had discussions in the past (see w3c/wot-scripting-api#106) and node-wot now enforces a check (and refuses) before writing a value that is readOnly (see PR #328).
Note1: this means once a property is readOnly we need to write a property read handler
Note2: only if a property is writable we can use the built-in value bucket.

Let's assume we have the following TD for a property counter that indicates it is readOnly.

    properties: {
        count: {
            type: "integer",
            description: "current counter value",
            readOnly: true
        }

The node wot runtime can not detect whether a thing.writeProperty("count", 0) comes from outside OR the script that initiated the exposed thing. Hence I do not see any other solution than handling the count value separately as I did in the PR #335.

@egekorkan @relu91 any opinion? I believe there are other scripts out there that used it before and will fail now.
@zolkis do you see a way the situation can be improved (relates to w3c/wot-scripting-api#106)

@egekorkan
Copy link
Member

I think that this makes more sense however this is a breaking change, i.e. now I have to rewrite all my Thing implementations :( Such changes require a more significant version update than incrementing the patch number

@danielpeintner
Copy link
Member

I think that this makes more sense however this is a breaking change, i.e. now I have to rewrite all my Thing implementations :( Such changes require a more significant version update than incrementing the patch number

We can also "hold back/revert" this change till v0.8.x is ready (which will be soon) ...

The overall question remains whether this is how it is meant to work.

@relu91
Copy link
Member

relu91 commented Sep 25, 2020

I think if the designer decides that it is a readonly property we should not allow writings. It would be counterintuitive in my opinion... Anyway, there's always the argument that those tags are just suggestions and should not be taken as constraints. I personally like the current node-wot approach, so that as a developer I can fine-tune the visibility of certain properties. However, I am open to other options 😄 .

@egekorkan
Copy link
Member

I also think that they should not be writable by outsider Consumers but it is really convenient to be able to write to properties internally instead of needing to create variables and manage them. This breaking change even requires me to write extra read handlers if I am reading values from a sensor every second and storing them in a property.

@egekorkan
Copy link
Member

However, there is no need to fix it if there will be no npm publishes until the version 0.8.x

@zolkis
Copy link

zolkis commented Sep 28, 2020

Writing a property is implemented internally in the implementation script.
In my view, writeProperty() is always a client method.
So the impl script should use its own internal method for writing, if it wants to override the TD semantics.
All the others should not be able to write a read-only property.
See also my comment in that issue.

@danielpeintner
Copy link
Member

However, there is no need to fix it if there will be no npm publishes until the version 0.8.x

@egekorkan this is already part of published node-wot v0.7.2 (see PR #328)
We could revert this for v0.7.3 and bring it back for v0.8.x but I am not sure this is the right way forward

@egekorkan
Copy link
Member

If we do this, how can we emit observable property "events"? Since the new property value is emitted when it is written to, should an implementation come up with its own way of emitting a new property value?

@zolkis
Copy link

zolkis commented Sep 28, 2020

how can we emit observable property "events"? Since the new property value is emitted when it is written to

Not sure if I get the use case. I see 2 use cases.

  1. If an ExposedThing script exposes a local read-only (for clients!) Property, which changes value (updated by internal method), then of course it is possible to subscribe to it and when the internal write method is called, it can notify subscribers.

In the ExposedThing script, the writeProperty() method (and the whole ConsumedThing interface) is local (see the spec text, and the script can implement it the way it wants, probably invoking a local library. In some cases it can be generated by using local protocol bindings and using the init dictionary passed in produce(), but that's a lucky case and an implementation detail. In principle it's a private local method in the context of ExposedThing.

  1. If you implement an ExposedThing proxy that exposes a read-only (for clients) Property, then of course it should be able to write that property over the network interface. The use case is to re-expose a Thing that has a readable Property (say, in a given local network) as a Thing with a read-only Property to all other external clients.

If there is a Thing that exposes a read-only Property, the API contract is that writeProperty() must fail on it, full stop. But that does not necessarily mean a client cannot subscribe to value changes on that Property.

@egekorkan
Copy link
Member

So I am more on the first use case you describe, I think. Here is an example Thing implementation that has an observable property:
https://github.com/tum-esi/wot-sys/blob/master/Devices/nodewot-infrared-sensor-dobot/src/base.ts

On line 85, once the infrared sensor detects an object, the value is written to the property and this line alone results in the emission of an observed property event. How can this be achieved without leaving the Scripting API context if the property cannot be written to in the same script that exposes it?

@danielpeintner
Copy link
Member

On line 85, once the infrared sensor detects an object, the value is written to the property and this line alone results in the emission of an observed property event. How can this be achieved without leaving the Scripting API context if the property cannot be written to in the same script that exposes it?

I think it still fires notification of value changes. See https://github.com/eclipse/thingweb.node-wot/blob/8ee006a971e45dded6cf2d7df0256dec512b5eb9/packages/core/src/exposed-thing.ts#L244 where it fires this event even if a handler is used or do I miss anything here?

@zolkis
Copy link

zolkis commented Sep 29, 2020

if the property cannot be written to in the same script that exposes it

It can be written by the local methods of the script, if the matching entity is locally writeable.
It can be even written by the local writeProperty() method in ExposedThing, since that is anyway a local method. (The two can be the same).

Where the writing SHOULD fail is all the incoming write requests to that Property, i.e. all the remote client writeProperty() calls.

Currently the API spec doesn't have steps for handling readonly enforcement, that is currently an implementation detail, since the script doesn't know whether a Property has a local binding (via a library) or is accessed via a network interface.
We could add a note in the ConsumedThing algorithms about this.

@danielpeintner
Copy link
Member

keep issue open for discussions to settle

@egekorkan
Copy link
Member

It can be written by the local methods of the script, if the matching entity is locally writeable.

I agree with this and it still would fire if it could be written to locally.

I totally agree that anything coming over the network should not be allowed to write to a readOnly property

@egekorkan
Copy link
Member

Some further comments:

  • where it fires this event even if a handler is used or do I miss anything here?

This part is never triggered since the following check is valid for a readOnly property, thus the reject happens on the following line:
https://github.com/eclipse/thingweb.node-wot/blob/8ee006a971e45dded6cf2d7df0256dec512b5eb9/packages/core/src/exposed-thing.ts#L226

  • It seems that writeOnly properties can be read? #326 has introduced this behavior. In my opinion, this is a bug since we cannot emit observed property's new values. Whether we should allow internal writes is one question, how we emit observed properties is another one.
    • If we allow writeProperty internally, the second question is answered.
    • If we do not allow it, a method like updateProperty is needed that can be standardized or left to be implementation-specific.

@relu91
Copy link
Member

relu91 commented Oct 30, 2020

I agree that we need to solve this. I tempted to go with the first solution: allow writeProperty internally,. It is straightforward and does not need any changes in the API. However, I am afraid that it is a violation of the Liskov Substitution Principle. Since ExposedThing is a subclass of ConsumedThing the ExposedThing writeProperty method should not be less strict than the ConsumeThing writeProperty method. What do you think? I'd expect that with the same inputs both methods should fail.

Having said that I think we should go with the second option: add a updateProperty method. We could explore it in node-wot and then add to the Scripting API note.

@egekorkan
Copy link
Member

Since ExposedThing is a subclass of ConsumedThing the ExposedThing writeProperty method should not be less strict than the ConsumeThing writeProperty method.

Yes, I agree that it is confusing that such a way exists. One may never notice that this is possible since you would be used to not use writeProperty for readOnly properties. Regarding updateProperty: I have thought of this but having a method that does not associate with a WoT operation is slightly unusual. Also, for a first time reader, the difference between writeProperty and updateProperty might not be obvious.

In any case, a solution is needed :)

@zolkis
Copy link

zolkis commented Oct 31, 2020

ExposedThing implements all its methods, including writeProperty, and as I said above, they are basically local private methods.
So the semantics does not go beyond local scope. In fact, the ExposedThing implementation doesn't need them.
The runtime should not implement writeProperty in ExposedThing, the script has to, as it defines the ExposedThing.

I am even thinking to remove the inheritance and its spec, as it seems confusing. They are all local convenience methods, not really needed.
ExposedThing exposes a Thing definition of a local (or proxied) entity. ConsumeThing represents a remote or local Thing. But it cannot represent a local Thing that is being defined. It's a chicken-egg problem.
Only after an ExposedThing is exposed, a ConsumedThing could be made to represent it.

@danielpeintner
Copy link
Member

I guess "what" we try to achieve is to differentiate between the writeProperty() of externals/clients and writeProperty() of the script itself. The first should not be allowed for readOnly properties while the latter should just work fine.

I wonder how we can achieve that. What could be the best means to differentiate the two cases?

  • other method like updateProperty()
  • change/avoid subclassing (ConsumedThing vs. ExposedThing)
  • handing over some internal knowledge that classifies the call to be internal and able to write? What could bu such magic?
  • ...

So far I can't really come up with a good proposal either :-(

@zolkis
Copy link

zolkis commented Nov 4, 2020

The idea with ExposedThing is that a script implements it.
The idea with ConsumedThing inherited in ExposedThing was that of convenience, i.e. its implementation could be "generated" by the runtime for local use, however, the script could override it.
It seems it creates more confusion than problem solving, so let's apply Occam's razor.
I suggest we step back a little in order to gain experience whether we really need ConsumedThing interface inside ExposedThing. I have the hunch it's not needed, but later we can add back things easily.

This will not break any existing code, since local/private ConsumedThing functions could be still implemented on ExposedThing. Only that we'd not specify it that way. It's a relatively minor change in the spec.

@relu91
Copy link
Member

relu91 commented Nov 5, 2020

The idea with ExposedThing is that a script implements it.

Totally agree here. However, I think the current API lacks the means to convey that a property value has changed. Therefore, we can't really implement an ExposedThing. Currently, it was done implicitly by the writeProperty method, but I do not think this is the right approach. I propose to add this new method:

interface ExposedThing {
     async emitPropertyChange(property:string):void;
}

Basically, we don't duplicate the writeProperty method semantics (e.g. adding a updateProperty method), but we introduce a point where script developers can convey to property subscribers that something has changed. This is very similar to what we are doing with emitEvent method and it makes much more sense to me than the current situation.

Once we have this new method, we could enforce the fact that if a property is a readOnly, writeProperty will always fail (even locally). On the other, we could define a default WriteHandler that automatically calls the emitPropertyChange when the new value is different from the previous.

What do you think?

p.s. to me this is pretty similar to what is done in other APIs like Observers in Java and .Net propertyChanged events.

@egekorkan
Copy link
Member

egekorkan commented Nov 5, 2020

I am almost totally fine with the above mentioned solution. One thing that bugs me is that before it was inherently assured that the property changes were emitted. Now, it would be up to the developer to do that. It might be better since maybe you don't want to emit every change but want to change the internal value very often.

In any case, the way it was introduced in a minor version is breaking a lot of my stuff that used the ^ notation for versioning.

@zolkis
Copy link

zolkis commented Nov 5, 2020

@relu91 : the current API lacks the means to convey that a property value has changed

I assumed that part could be encapsulated by the implementation, once it has the list of Property observers.
So what it needs to know is when a property is changed. But it has no way to know it without a hook, which writeProperty() was supposed to be (the impl knew it was called, of course with the script-provided content, but here only the fact of invocation mattered). Since I suggest removing the ConsumedThing inheritance, we need something else, so your proposal makes sense.
That would allow the scripts to totally control the Property observe notifications, like with Events, and that makes even more sense. So I fully support it. Actually it's a natural consequence of removing ConsumedThing inheritance from ExposedThing.

@egekorkan: the way it was introduced in a minor version is breaking a lot of my stuff that used the ^ notation for versioning

Versioning of the Scripting API (from the spec, propagated to implementations) is under discussion, your suggestions would be welcome on that.

@relu91
Copy link
Member

relu91 commented Nov 5, 2020

So what it needs to know is when a property is changed. But it has no way to know it without a hook, which writeProperty() was supposed to be

That's precisely why I made my proposal.

Since I suggest removing the ConsumedThing inheritance, we need something else, so your proposal makes sense.
That would allow the scripts to totally control the Property observe notifications, like with Events, and that makes even more sense. So I fully support it. Actually it's a natural consequence of removing ConsumedThing inheritance from ExposedThing.

I guess we could still live with ConsumeThing -> ExposedThing inheritance. I still find it convenient to pass around an ExposedThing instance to methods/functions that expect a ConsumeThing. But if others can't stand it we could drop the relation.

Versioning of the Scripting API (from the spec, propagated to implementations) is under discussion, your suggestions would be welcome on that.

I think @egekorkan was talking about node-wot versioning. I think the problem was that after the #328 we increased the patch number of node-wot version. This broke every Ege's script since they were dependent to ^0.7.0 (which basically means every version with 7 as minor). @egekorkan correct? I guess the problem right now is that we can't increase the maior because we are working on the 0.8.0 as the version with the new API. When we finally have the new apis we have more room to change the version number. @danielpeintner correct?

Versioning of the Scripting API (from the spec, propagated to implementations) is under discussion, your suggestions would be welcome on that.

Anyhow, this issue is still standing.

@egekorkan
Copy link
Member

I think @egekorkan was talking about node-wot versioning.

Yes :)

By the way, for the emitPropertyChange(property:string), should it emit a value given to it? Should that value also change the value gotten by a readProperty function? Also, can it emit even if it didn't change? I think there are some open points that need to be very well defined.

@relu91
Copy link
Member

relu91 commented Nov 5, 2020

We should think about it, but I feel like it does not need a value. The platform should use the read handler defined for that property and get the value back from there. No change to the value should happen here. Then the runtimes MAY (?) cache previous values and send the event only if a real change happened.

@zolkis
Copy link

zolkis commented Nov 5, 2020

I still find it convenient to pass around an ExposedThing instance to methods/functions that expect a ConsumeThing.

We could use the TD instance of an ExposedThing and create a ConsumedThing from that. Basically we end up with the same thing, but a bit more separated and better defined.

@zolkis
Copy link

zolkis commented Nov 5, 2020

Should that value also change the value gotten by a readProperty function?

That might depend on the binding, too. In OCF/CoAP binding, on the client side, the property change notification must indeed provide the value as well. Next reads would return the same value, until the next change. We can handle this the same way we handle a read, i.e. using the InteractionOutput interface or by passing null. But I can imagine in some protocols only the notification will go, requiring a subsequent read.

@egekorkan
Copy link
Member

Ah ok, so if I get it correctly, I would need to do something like the following:

var myTemp = 25;

thing1.setPropertyReadHandler("temperature", () => {
     resolve(myTemp);
});

thing1.setActionHandler("increaseTemperature", () => {
    myTemp = myTemp +2;
    emitPropertyChange("temperature"); //actually emits since the value returned by myTemp has changed
    resolve();
  });

It is not bad but the developer needs to remember the relation between myTemp (or a function that used by the property read handler) and the property in other places when using emitPropertyChange. I think it is an acceptable solution though :)

@zolkis
Copy link

zolkis commented Nov 5, 2020

You could add a convenience function,

thing1.updateTemperature = (value) => {
  await updateLocalTemperature(value);
  await emitPropertyChange("temperature", value);
}; 

and use updateTemperature() instead of the + operator.
(NB, updateTemperature(value) was called the more generic writeProperty("temperature", value) in the current API, which we can also do.)

@relu91
Copy link
Member

relu91 commented Nov 5, 2020

@egekorkan the example looks good to me and I think the shortcomings that you mentioned are not that bad.

@zolkis
Copy link

zolkis commented Nov 5, 2020

Meanwhile we are discussing to remove ConsumedThing inheritance from ExposedThing, but resolve expose() with that ConsumedThing. That would clarify things and maintain convenience. expose() could even take an option to skip generating that ConsumedThing, if not needed.

@danielpeintner
Copy link
Member

Comments w.r.t. to the example given by Ege here

I think in the case of using built-in value containers it should be much simpler. Hence, if no user-defined write handler is set we should be able to just say say write/updateProperty() and the emitPropertyChange() should be called internally.

Once a dedicated write handler is set the task of doing the right calls is shifted to the developer.

Having said that, I think we might want to differentiate the 2 cases...

@relu91
Copy link
Member

relu91 commented Nov 9, 2020

I think in the case of using built-in value containers it should be much simpler. Hence, if no user-defined write handler is set we should be able to just say say write/updateProperty() and the emitPropertyChange() should be called internally.

I think Ege was thinking about the readonly use case where it does not really make sense to allow writeProperty to do its job. On the other hand, if we are talking about a writable property, I think that the default should like you are proposing (i.e. call emitPropertyChange internally)

@zolkis
Copy link

zolkis commented Nov 9, 2020

Summarizing from the Scripting call today (Nov. 9. 2020),

  1. We should have emitPropertyChange() method in ExposedThing (scripting issue 280)

  2. We should remove ConsumedThing inheritance from ExposedThing because the confusions (scripting issue 281).
    After a long discussion we agree this is better since code will be portable and let's force writing ExposedThing using local means, before standardizing convenience for accessing the internal properties etc.

  3. We could have a convenience interface in ExposedThing that is usable by scripts to get and set the internal properties, actions, events. This would be like a getter/setter accessor API only (node-wot already does that internally). Obviously this won't have limitations, i.e. scripts could set even read-only properties, since it's local.
    For instance, if the script has a sensor read function that uses a local library, the value obtained from that function needs to be set to the property that represents that sensor in ExposedThing. This would also allow default (implementation generated) property read/write request handlers: implementations could read the internal values when serving requests.

@egekorkan
Copy link
Member

These are good improvements! :)

@zolkis
Copy link

zolkis commented Nov 9, 2020

About point 3, I do have some reservations. The request handlers are already meant to provide the values from sensors and are more generic (don't only provide the value, but also define how to handle the requests).

For an ExposedThing to work, the essential minimum is to provide the request handlers. Managing internal properties can be done locally by the script. One argument for the internal accessor interface was to make scripts more portable. However, I would argue the sensor specific parts of the script need to be ported anyway, so standardizing the trivially small part that writes values to internal slots/containers (also assuming there are internal containers, which is a local design decision) would not help much IMHO, it just introduces more complexity in the spec.

Right now, if a request handler is not defined, the implementation will signal error (OK, it could also implement a default handler, but currently we force it to return an error since the lack of understanding suitable default values, which depend on the semantics of the properties). Internal slots for properties may be optional (node-wot does implement them, others MAY skip that and provide values "on the fly"). But if we wanted that implementations could provide default handlers, we could do that with 1+2 as well.

If we introduce 3, the local accessor API + their associated mechanisms in ExposedThing, implementations SHOULD have internal slots for properties at least, and then scripts will have to follow a certain pattern. We could go as far as saying that if the script implements the internal updating of a property, and it doesn't want to define a special request handling, then it could skip defining the read request handler for that property, since all the implementation needs to do when a read request comes is to read the internal value (that was previously updated by the script) and return it in the reply. That is, implementations will have a default handler for Properties read requests, which invokes the script-defined request handlers (if defined) in order to provide the values, then in success case, update the internal slot with that value and reply to the request. In the case an update is made to an internal slot, it could automatically notify the listeners (making the need for emitPropertyChange() obsolete, i.e. point 1 is not needed).

So the programming style changes from an all-explicit scripting towards a "script only the special cases for properties" approach. That is quite a big change.

Also note that all this is only valid for Properties. Events may also carry data, but that is governed by the EventListenerHandler, similarly as for properties is now governed by PropertyReadHandler. Which makes the current API (1+2, without 3) simple (no default background mechanisms to understand and keep in mind) and coherent across handling Property, Event and Action interactions. But 1+2+3 (or 2+3) would make it far easier to create SW defined ExposedThings.

Basically we decided in the call to do only 1 and 2 for the moment. Please join the next Scripting call if you want to discuss 3 further. These are 2 different programming styles and developer feedback would be needed in order to move forward.

@relu91
Copy link
Member

relu91 commented Nov 9, 2020

  1. We should have emitPropertyChange() method in ExposedThing (scripting issue 280)
  2. We should remove ConsumedThing inheritance from ExposedThing because the confusions (scripting issue 281).
    After a long discussion we agree this is better since code will be portable and let's force writing ExposedThing using local means, before standardizing convenience for accessing the internal properties etc.

Let's go with it! 👍 . About point 3 (and actually the current implementation) I also have my concerns. Having the ability to store property values inside an ExposedThing instance might be convenient but it adds quite a lot of complexity to the runtime level. It is as if the runtime wants to predict how the properties should be served and also stored. In the end, this might lead to inefficiencies, like in one of our applications. We end up having for a property to have our own variable that keeps tracks of property values, plus the one inside the exposed thing.

To have a better separation of roles I'll implement this caching/stateful(?) feature on a different framework/library. I think our goal is to make the API as flexible/simple as possible so that developers could extend it to meet their own requirements. Therefore, an ExposeThing implementation should look like what is shown in @egekorkan 's comment.

@zolkis
Copy link

zolkis commented Nov 9, 2020

To have a better separation of roles I'll implement this caching/stateful(?) feature on a different framework/library.

That would make sense. It could be imported in a script and enjoy the convenience without cluttering the minimal Scripting spec.
It could extend ExposedThing and add convenience layers, starting from the constructor. If becomes well received, we could later include it in the Scripting spec.

@relu91
Copy link
Member

relu91 commented Nov 9, 2020

TLDR

Sorry, the post is pretty long. Summarizing, I am describing another edge use-case to have a ConsumeThing from an ExposedThing. This one is more about using an ExposedThing rather than defining it. I think could give it a try after we close point 1 and 2.

Another use-case for ConsumedThing in ExposedThing

Now about the whole Local interaction with an Exposed Thing subject, let me clarify the use case I had in mind in today's call. It is not related on how we define an ExposedThing but rather on how we can interact with it from the same script.

Let's assume that we have implement point 1,2 above. So we can't invoke myCoolThing.invokeAction("hello") or myCoolThing.readProperty("prop1") from an ExposedThing instance anymore. However, we can still fully describe an ExposedThing implementation thanks to local variables, handlers functions, and the newly introduced emitPropertyChange method.
Consider this simple WoT application:

Design an application that exposes Sensor 1 and Sensor 2 as Web Things plus a third WT that combines Sensor 1 and Sensor 2 to obtain a virtual sensor (e.g. Sensor 3)

File script1.js implements Sensor1 Web Thing and looks like this:

// ... define a TD, produce an ExposedThing called sensor ...

sensor.setPropertyReadHandler("temperature", sameFancyFunctionToReadSensor1);

// Other Handlers/configurations

Similarly, script2.js implements Sensor2.

Now to implement the remainder sensor a dev could:

  1. Use WoT abstraction and reuse the code defined in script1 and script2
  2. Use dev defined abstractions to use sensor1 and sensor2. (e.g. sameFancyFunctionToReadSensor1 function)

Either of the two options is perfectly reasonable. However, I see that option 1 has a greater advantage over the second: the same code will work even if Sensor1 or Sensor2 is not hosted in the same node. This means that the code that implements Sensor3 could be ported in different scenarios. For example, in applications where Sensor1 and Sensor 2 should be discovered at runtime and are not in the same node of Sensor 3.

So a possible implementation of Sensor3 could be something like the following:

function createSensor3( sensor1:ConsumedThing, sensor2:ConsumedThing){
    // Define Sensor3 TD and produce sensor3 ExposedThing
    sensor3.setPropertyReadHandler("value",async () => {
        return await sensor1.readProperty("value") + await sensor2.readProperty("value") // or other super complex combination of the values
    })
   return sensor3;
}

As mentioned, this exact same function could be used in an application that creates Sensor1 and Sensor2 or in another one that discovers Sensor1 and Sensor2 at runtime. This is the portability that I had in mind today. The good news is that we can still achieve this portability just with @zolkis's 1 and 2 points. However, there's a catch:

If I consume a TD exposed by an in-script ExposedThing I still have to interact with as in a client-server relationship.

This implies that I still waste resources to create an HTTP (or other protocol) request, serialize it in a socket, wait for the response, decode it, and finally get the result. However, we could optimize it by defining a LocalConsumedThing which talks directly with an ExposedThing backend (i.e. function handlers). This LocalConsumedThing would implement ConsumedThing interface and acts completely as if it was remote (i.e. writeProperty should fail if a property is not readable). As suggested by @zolkis we could get an instance of LocalConsumedThing as a result of an exposed operation, or it could be simply discovered by a special discovery filter.

Finally, probably also this use case falls under "it is a nice addition but it adds too much complexity to the runtime". However, I found it as a basic functionality that would increase code reuse and encourage good design patterns inside WoT applications.

@danielpeintner
Copy link
Member

I agree 1. and 2. seem sufficient and the convenience of 3. has been causing issues/confusion in the past.

@danielpeintner
Copy link
Member

w.r.t. node-wot: Shall we revert the change of #328 to avoid issues with running samples out there (version 0.7.x).
To me it seems reasonable since a revised API version will disallow this anyway (version 0.8.x).

@egekorkan would this help you?

@egekorkan
Copy link
Member

w.r.t. node-wot: Shall we revert the change of #328 to avoid issues with running samples out there (version 0.7.x).

Yes ! 😄

I agree 1. and 2. seem sufficient and the convenience of 3. has been causing issues/confusion in the past.

Me too.

@zolkis
Copy link

zolkis commented Nov 10, 2020

However, I see that option 1 has a greater advantage over the second: the same code will work even if Sensor1 or Sensor2 is not hosted in the same node.

This seems hypothetical to me, since the script is running in a single runtime, it cannot locally access sensors on other nodes.
But I get the theoretical point.

The optimal solution for that seems to be a full-fledged ConsumedThing interface that can use local bindings (optimization) when available.

Since we want to have that before exposing the Thing, we'd need to split the current expose() functionality into 2 parts: 1. just "compile" all bindings (a new function) and 2. to make the services public (new expose()) that would also do step 1 if it wasn't done before.

That new function would resolve with a locally bound ConsumedThing, with full semantics, meaning that you could not write a read-only property with that interface, even though it has local bindings. If you wanted to update a read-only property, you'd use your local private functions that have access to it.

If the implementation cannot make the optimizations to have "local bindings", the new function should fail (all its purpose is ConsumedThing-like local interface). In that case the script would need to consume() the ExposedThing after it is exposed, or just work with the private functions.

The nice thing about it is that it can be done on top of 1+2 and code won't break.

Does that sound good, and is it worth doing it?

danielpeintner added a commit to danielpeintner/thingweb.node-wot that referenced this issue Nov 10, 2020
API will change for v0.8.x anyway
see discussion in eclipse-thingweb#333
relu91 pushed a commit to relu91/thingweb.node-wot that referenced this issue Jun 1, 2021
API will change for v0.8.x anyway
see discussion in eclipse-thingweb#333

Signed-off-by: reluc <relu.cri@gmail.com>
@danielpeintner
Copy link
Member

The new scripting API and the according node-wot implementation does not have writeProperty() for ExposedThing any longer.

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

Successfully merging a pull request may close this issue.

5 participants