Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
Nodemcu Firmware
Commits
117df40f
Commit
117df40f
authored
Mar 28, 2016
by
Marcel Stör
Browse files
Merge pull request #1179 from pjsg/unsubscribe
MQTT Unsubscribe support
parents
bff75bc0
ab950ff5
Changes
4
Show whitespace changes
Inline
Side-by-side
app/modules/mqtt.c
View file @
117df40f
...
...
@@ -62,6 +62,7 @@ typedef struct lmqtt_userdata
int cb_disconnect_ref;
int cb_message_ref;
int cb_suback_ref;
int cb_unsuback_ref;
int cb_puback_ref;
mqtt_state_t mqtt_state;
mqtt_connect_info_t connect_info;
...
...
@@ -124,11 +125,9 @@ static void mqtt_socket_disconnected(void *arg) // tcp only
mud->pesp_conn = NULL;
}
if
(
mud
->
self_ref
!=
LUA_NOREF
){
// TODO: should we unref the client and delete it?
luaL_unref(L, LUA_REGISTRYINDEX, mud->self_ref);
mud->self_ref = LUA_NOREF; // unref this, and the mqtt.socket userdata will delete it self
}
}
if(call_back){
lua_call(L, 1, 0);
...
...
@@ -363,6 +362,14 @@ READPACKET:
if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && pending_msg->msg_id == msg_id){
NODE_DBG("MQTT: UnSubscribe successful\r\n");
msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q)));
if (mud->cb_unsuback_ref == LUA_NOREF)
break;
if (mud->self_ref == LUA_NOREF)
break;
lua_rawgeti(L, LUA_REGISTRYINDEX, mud->cb_unsuback_ref);
lua_rawgeti(L, LUA_REGISTRYINDEX, mud->self_ref);
lua_call(L, 1, 0);
}
break;
case MQTT_MSG_TYPE_PUBLISH:
...
...
@@ -823,35 +830,21 @@ static int mqtt_delete( lua_State* L )
// -------
// free (unref) callback ref
if
(
LUA_NOREF
!=
mud
->
cb_connect_ref
){
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_connect_ref);
mud->cb_connect_ref = LUA_NOREF;
}
if
(
LUA_NOREF
!=
mud
->
cb_connect_fail_ref
){
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_connect_fail_ref);
mud->cb_connect_fail_ref = LUA_NOREF;
}
if
(
LUA_NOREF
!=
mud
->
cb_disconnect_ref
){
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_disconnect_ref);
mud->cb_disconnect_ref = LUA_NOREF;
}
if
(
LUA_NOREF
!=
mud
->
cb_message_ref
){
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_message_ref);
mud->cb_message_ref = LUA_NOREF;
}
if
(
LUA_NOREF
!=
mud
->
cb_suback_ref
){
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_suback_ref);
mud->cb_suback_ref = LUA_NOREF;
}
if
(
LUA_NOREF
!=
mud
->
cb_puback_ref
){
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_puback_ref);
mud->cb_puback_ref = LUA_NOREF;
}
lua_gc(L, LUA_GCSTOP, 0);
if
(
LUA_NOREF
!=
mud
->
self_ref
){
luaL_unref(L, LUA_REGISTRYINDEX, mud->self_ref);
mud->self_ref = LUA_NOREF;
}
lua_gc(L, LUA_GCRESTART, 0);
NODE_DBG("leave mqtt_delete.\n");
return 0;
...
...
@@ -1060,7 +1053,6 @@ static int mqtt_socket_connect( lua_State* L )
// call back function when a connection is obtained, tcp only
if ((stack<=top) && (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION)){
lua_pushvalue(L, stack); // copy argument (func) to the top of stack
if
(
mud
->
cb_connect_ref
!=
LUA_NOREF
)
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_connect_ref);
mud->cb_connect_ref = luaL_ref(L, LUA_REGISTRYINDEX);
stack++;
...
...
@@ -1069,14 +1061,12 @@ static int mqtt_socket_connect( lua_State* L )
// call back function when a connection fails
if ((stack<=top) && (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION)){
lua_pushvalue(L, stack); // copy argument (func) to the top of stack
if
(
mud
->
cb_connect_fail_ref
!=
LUA_NOREF
)
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_connect_fail_ref);
mud->cb_connect_fail_ref = luaL_ref(L, LUA_REGISTRYINDEX);
stack++;
}
lua_pushvalue(L, 1); // copy userdata to the top of stack
if
(
mud
->
self_ref
!=
LUA_NOREF
)
luaL_unref(L, LUA_REGISTRYINDEX, mud->self_ref);
mud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
...
...
@@ -1182,15 +1172,12 @@ static int mqtt_socket_on( lua_State* L )
lua_pushvalue(L, 3); // copy argument (func) to the top of stack
if( sl == 7 && c_strcmp(method, "connect") == 0){
if
(
mud
->
cb_connect_ref
!=
LUA_NOREF
)
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_connect_ref);
mud->cb_connect_ref = luaL_ref(L, LUA_REGISTRYINDEX);
}else if( sl == 7 && c_strcmp(method, "offline") == 0){
if
(
mud
->
cb_disconnect_ref
!=
LUA_NOREF
)
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_disconnect_ref);
mud->cb_disconnect_ref = luaL_ref(L, LUA_REGISTRYINDEX);
}else if( sl == 7 && c_strcmp(method, "message") == 0){
if
(
mud
->
cb_message_ref
!=
LUA_NOREF
)
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_message_ref);
mud->cb_message_ref = luaL_ref(L, LUA_REGISTRYINDEX);
}else{
...
...
@@ -1201,6 +1188,118 @@ static int mqtt_socket_on( lua_State* L )
return 0;
}
// Lua: bool = mqtt:unsubscribe(topic, function())
static int mqtt_socket_unsubscribe( lua_State* L ) {
NODE_DBG("enter mqtt_socket_unsubscribe.\n");
uint8_t stack = 1;
uint16_t msg_id = 0;
const char *topic;
size_t il;
lmqtt_userdata *mud;
mud = (lmqtt_userdata *) luaL_checkudata( L, stack, "mqtt.socket" );
luaL_argcheck( L, mud, stack, "mqtt.socket expected" );
stack++;
if(mud==NULL){
NODE_DBG("userdata is nil.\n");
lua_pushboolean(L, 0);
return 1;
}
if(mud->pesp_conn == NULL){
NODE_DBG("mud->pesp_conn is NULL.\n");
lua_pushboolean(L, 0);
return 1;
}
if(!mud->connected){
luaL_error( L, "not connected" );
lua_pushboolean(L, 0);
return 1;
}
uint8_t temp_buffer[MQTT_BUF_SIZE];
mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE);
mqtt_message_t *temp_msg = NULL;
if( lua_istable( L, stack ) ) {
NODE_DBG("unsubscribe table\n");
lua_pushnil( L ); /* first key */
int topic_count = 0;
uint8_t overflow = 0;
while( lua_next( L, stack ) != 0 ) {
topic = luaL_checkstring( L, -2 );
if (topic_count == 0) {
temp_msg = mqtt_msg_unsubscribe_init( &mud->mqtt_state.mqtt_connection, &msg_id );
}
temp_msg = mqtt_msg_unsubscribe_topic( &mud->mqtt_state.mqtt_connection, topic );
topic_count++;
NODE_DBG("topic: %s - length: %d\n", topic, temp_msg->length);
if (temp_msg->length == 0) {
lua_pop(L, 1);
overflow = 1;
break; // too long message for the outbuffer.
}
lua_pop( L, 1 );
}
if (topic_count == 0){
return luaL_error( L, "no topics found" );
}
if (overflow != 0){
return luaL_error( L, "buffer overflow, can't enqueue all unsubscriptions" );
}
temp_msg = mqtt_msg_unsubscribe_fini( &mud->mqtt_state.mqtt_connection );
if (temp_msg->length == 0) {
return luaL_error( L, "buffer overflow, can't enqueue all unsubscriptions" );
}
stack++;
} else {
NODE_DBG("unsubscribe string\n");
topic = luaL_checklstring( L, stack, &il );
stack++;
if( topic == NULL ){
return luaL_error( L, "need topic name" );
}
temp_msg = mqtt_msg_unsubscribe( &mud->mqtt_state.mqtt_connection, topic, &msg_id );
}
if( lua_type( L, stack ) == LUA_TFUNCTION || lua_type( L, stack ) == LUA_TLIGHTFUNCTION ) { // TODO: this will overwrite the previous one.
lua_pushvalue( L, stack ); // copy argument (func) to the top of stack
luaL_unref( L, LUA_REGISTRYINDEX, mud->cb_unsuback_ref );
mud->cb_unsuback_ref = luaL_ref( L, LUA_REGISTRYINDEX );
}
msg_queue_t *node = msg_enqueue( &(mud->mqtt_state.pending_msg_q), temp_msg,
msg_id, MQTT_MSG_TYPE_UNSUBSCRIBE, (int)mqtt_get_qos(temp_msg->data) );
NODE_DBG("topic: %s - id: %d - qos: %d, length: %d\n", topic, node->msg_id, node->publish_qos, node->msg.length);
NODE_DBG("msg_size: %d, event_timeout: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q)), mud->event_timeout);
sint8 espconn_status = ESPCONN_IF;
espconn_status = mqtt_send_if_possible(mud->pesp_conn);
if(!node || espconn_status != ESPCONN_OK){
lua_pushboolean(L, 0);
} else {
lua_pushboolean(L, 1); // enqueued succeed.
}
NODE_DBG("unsubscribe, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q)));
NODE_DBG("leave mqtt_socket_unsubscribe.\n");
return 1;
}
// Lua: bool = mqtt:subscribe(topic, qos, function())
static int mqtt_socket_subscribe( lua_State* L ) {
NODE_DBG("enter mqtt_socket_subscribe.\n");
...
...
@@ -1292,7 +1391,6 @@ static int mqtt_socket_subscribe( lua_State* L ) {
if( lua_type( L, stack ) == LUA_TFUNCTION || lua_type( L, stack ) == LUA_TLIGHTFUNCTION ) { // TODO: this will overwrite the previous one.
lua_pushvalue( L, stack ); // copy argument (func) to the top of stack
if
(
mud
->
cb_suback_ref
!=
LUA_NOREF
)
luaL_unref( L, LUA_REGISTRYINDEX, mud->cb_suback_ref );
mud->cb_suback_ref = luaL_ref( L, LUA_REGISTRYINDEX );
}
...
...
@@ -1368,7 +1466,6 @@ static int mqtt_socket_publish( lua_State* L )
if (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION){
lua_pushvalue(L, stack); // copy argument (func) to the top of stack
if
(
mud
->
cb_puback_ref
!=
LUA_NOREF
)
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_puback_ref);
mud->cb_puback_ref = luaL_ref(L, LUA_REGISTRYINDEX);
}
...
...
@@ -1475,6 +1572,7 @@ static const LUA_REG_TYPE mqtt_socket_map[] = {
{ LSTRKEY( "close" ), LFUNCVAL( mqtt_socket_close ) },
{ LSTRKEY( "publish" ), LFUNCVAL( mqtt_socket_publish ) },
{ LSTRKEY( "subscribe" ), LFUNCVAL( mqtt_socket_subscribe ) },
{ LSTRKEY( "unsubscribe" ), LFUNCVAL( mqtt_socket_unsubscribe ) },
{ LSTRKEY( "lwt" ), LFUNCVAL( mqtt_socket_lwt ) },
{ LSTRKEY( "on" ), LFUNCVAL( mqtt_socket_on ) },
{ LSTRKEY( "__gc" ), LFUNCVAL( mqtt_delete ) },
...
...
app/mqtt/mqtt_msg.c
View file @
117df40f
...
...
@@ -447,20 +447,40 @@ mqtt_message_t* mqtt_msg_subscribe(mqtt_connection_t* connection, const char* to
return
result
;
}
mqtt_message_t
*
mqtt_msg_unsubscribe
(
mqtt_connection_t
*
connection
,
const
char
*
topic
,
uint16_t
*
message_id
)
mqtt_message_t
*
mqtt_msg_unsubscribe
_init
(
mqtt_connection_t
*
connection
,
uint16_t
*
message_id
)
{
init_message
(
connection
);
return
mqtt_msg_subscribe_init
(
connection
,
message_id
);
}
mqtt_message_t
*
mqtt_msg_unsubscribe_topic
(
mqtt_connection_t
*
connection
,
const
char
*
topic
)
{
if
(
topic
==
NULL
||
topic
[
0
]
==
'\0'
)
return
fail_message
(
connection
);
if
((
*
message_id
=
append_message_id
(
connection
,
0
))
==
0
)
return
fail_message
(
connection
);
if
(
append_string
(
connection
,
topic
,
c_strlen
(
topic
))
<
0
)
return
fail_message
(
connection
);
return
fini_message
(
connection
,
MQTT_MSG_TYPE_SUBSCRIBE
,
0
,
1
,
0
);
return
&
connection
->
message
;
}
mqtt_message_t
*
mqtt_msg_unsubscribe_fini
(
mqtt_connection_t
*
connection
)
{
return
fini_message
(
connection
,
MQTT_MSG_TYPE_UNSUBSCRIBE
,
0
,
1
,
0
);
}
mqtt_message_t
*
mqtt_msg_unsubscribe
(
mqtt_connection_t
*
connection
,
const
char
*
topic
,
uint16_t
*
message_id
)
{
mqtt_message_t
*
result
;
result
=
mqtt_msg_unsubscribe_init
(
connection
,
message_id
);
if
(
result
->
length
!=
0
)
{
result
=
mqtt_msg_unsubscribe_topic
(
connection
,
topic
);
}
if
(
result
->
length
!=
0
)
{
result
=
mqtt_msg_unsubscribe_fini
(
connection
);
}
return
result
;
}
mqtt_message_t
*
mqtt_msg_pingreq
(
mqtt_connection_t
*
connection
)
...
...
app/mqtt/mqtt_msg.h
View file @
117df40f
...
...
@@ -140,6 +140,10 @@ mqtt_message_t* mqtt_msg_subscribe_init(mqtt_connection_t* connection, uint16_t*
mqtt_message_t
*
mqtt_msg_subscribe_topic
(
mqtt_connection_t
*
connection
,
const
char
*
topic
,
int
qos
);
mqtt_message_t
*
mqtt_msg_subscribe_fini
(
mqtt_connection_t
*
connection
);
mqtt_message_t
*
mqtt_msg_unsubscribe_init
(
mqtt_connection_t
*
connection
,
uint16_t
*
message_id
);
mqtt_message_t
*
mqtt_msg_unsubscribe_topic
(
mqtt_connection_t
*
connection
,
const
char
*
topic
);
mqtt_message_t
*
mqtt_msg_unsubscribe_fini
(
mqtt_connection_t
*
connection
);
#ifdef __cplusplus
}
...
...
docs/en/modules/mqtt.md
View file @
117df40f
...
...
@@ -184,3 +184,28 @@ m:subscribe("/topic",0, function(conn) print("subscribe success") end)
-- or subscribe multiple topic (topic/0, qos = 0; topic/1, qos = 1; topic2 , qos = 2)
m
:
subscribe
({[
"topic/0"
]
=
0
,[
"topic/1"
]
=
1
,
topic2
=
2
},
function
(
conn
)
print
(
"subscribe success"
)
end
)
```
## mqtt.client:unsubscribe()
Unsubscribes from one or several topics.
#### Syntax
`mqtt:unsubscribe(topic[, function(client)])`
`mqtt:unsubscribe(table[, function(client)])`
#### Parameters
-
`topic`
a
[
topic string
](
http://www.hivemq.com/blog/mqtt-essentials-part-5-mqtt-topics-best-practices
)
-
`table`
array of 'topic, anything' pairs to unsubscribe from
-
`function(client)`
optional callback fired when unsubscription(s) succeeded
#### Returns
`true`
on success,
`false`
otherwise
#### Example
```
lua
-- unsubscribe topic
m
:
unsubscribe
(
"/topic"
,
function
(
conn
)
print
(
"unsubscribe success"
)
end
)
-- or unsubscribe multiple topic (topic/0; topic/1; topic2)
m
:
unsubscribe
({[
"topic/0"
]
=
0
,[
"topic/1"
]
=
0
,
topic2
=
"anything"
},
function
(
conn
)
print
(
"unsubscribe success"
)
end
)
```
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment