summaryrefslogtreecommitdiff
path: root/src/librygel-server/rygel-trackable-container.vala
blob: 96af497aa611f1caa57aacfd60cab40c90c3657f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
 * Copyright (C) 2012,2013 Intel Corporation.
 *
 * Author: Jens Georg <jensg@openismus.com>
 *
 * Rygel is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Rygel is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/**
 * The base class for containers that provide automatic change tracking.
 *
 * Derived classes should implement the add_child() and remove_child()
 * virtual functions to keep track of child items and child containers.
 *
 * Rygel server plugins (See #RygelMediaServer) may then call
 * rygel_trackable_container_add_child_tracked() and
 * rygel_trackable_container_remove_child_tracked() to add and remove
 * items, which will then cause the #RygelContainer::container_updated signal
 * to be emitted.
 */
public interface Rygel.TrackableContainer : Rygel.MediaContainer {
    public async void clear () {
        try {
            var children = yield this.get_children (0,
                                                    -1,
                                                    this.sort_criteria,
                                                    null);

            if (children == null) {
                return;
            }

            foreach (var child in children) {
                yield this.remove_child_tracked (child);
            }
        } catch (Error error) {
            warning (/*_*/("Failed to clear trackable container %s: %s"),
                     id,
                     error.message);
        }
    }

    /**
     * Derived classes should implement this, keeping track
     * of the child item or child container.
     * See the remove_child() virtual function.
     */
    protected abstract async void add_child (MediaObject object);
    protected signal void child_added (MediaObject object);
    protected signal void child_removed (MediaObject object);

    /**
     * Add a child object, emitting the #RygelContainer::container_updated signal
     * with the object.
     * @see rygel_trackable_object_remove_child_tracked()
     *
     * @param object The child item or child container to be added.
     */
    public async void add_child_tracked (MediaObject object) {
        yield this.add_child (object);

        this.updated (object, ObjectEventType.ADDED);
        this.updated ();
        if (object is TrackableContainer) {
            var trackable = object as TrackableContainer;

            // Release the events that might have accumulated
            trackable.thaw_events ();
        }
        this.child_added (object);
    }

    /**
     * Derived classes should implement this, removing the
     * child item or child container from its set of objects.
     * See the add_child() virtual function.
     */
    protected abstract async void remove_child (MediaObject object);

    /**
     * Add a child object, emitting the #RygelContainer::container_updated signal
     * with the object.
     * @see rygel_trackable_object_add_child_tracked()
     *
     * @param object The child item or child container to be added.
     */
    public async void remove_child_tracked (MediaObject object) {
        // We need to descend into this to get the proper events
        if (object is TrackableContainer) {
            var trackable = object as TrackableContainer;
            yield trackable.clear ();
        }

        yield this.remove_child (object);

        this.updated (object, ObjectEventType.DELETED);
        this.total_deleted_child_count++;

        // FIXME: Check if modification of child_count should lead to
        // LastChange event.
        this.updated ();
        this.child_removed (object);
    }

    /**
     * Used to query the (persisted) service reset token from the plug-in.
     *
     * If a plugin implements PLUGIN_CAPABILITIES_TRACK_CHANGES, it should
     * persist the ServiceResetToken. To do this override this virtual
     * function in the root container implementation and provide the persisted
     * version.
     */
    public virtual string get_service_reset_token () {
        return UUID.get ();
    }

    /**
     * Set a new service reset token.
     *
     * If the service reset procedure has to be performed, the content
     * directory service will set the new service reset token.
     *
     * @param token the new service reset token.
     */
    public virtual void set_service_reset_token (string token) {}

    /**
     * Query the current system update ID,
     * used for the UPnP GetSystemUpdateID implementation.
     *
     * This should be overriden by the root container of the back-end
     * implementation. This will only be called once, at service startup, 
     * to discover the cached system Update ID, if any, that was known
     * when the service last shut down.
     *
     * Derived classes may need to delay part of their initialization
     * until this function has been called, doing that initialization in
     * the function override. That can prevent other parts of their 
     * implementation from changing the cached System Update ID before
     * it has been provided.
     *
     * @return the current SystemUpdateID as persisted by the back-end.
     */
    public virtual uint32 get_system_update_id () { return 0; }

    private void thaw_events () {
        // Forward events.
    }
}