提交 99ca26f9 编写于 作者: Huan (李卓桓)'s avatar Huan (李卓桓)

#32 group add/del

上级 d3d1ae34
......@@ -3809,7 +3809,11 @@ angular.module("Services", []),
}).error(function() {}),
i.promise
},
pickContacts: function(e, t, o) {
pickContacts: function(
e: string[]
, t: {} filter
, o: boolean?
) {
for (var n, r, a, i = [], c = this, s = t.all || {}, l = 0; l < e.length; l++)
switch (n = e[l],
a = t[n] || {},
......
......@@ -26,6 +26,7 @@
"testdev": "cross-env LC_ALL=C WECHATY_LOG=silly ava --serial --verbose --fail-fast --timeout=3m",
"ava": "cross-env LC_ALL=C WECHATY_LOG=verbose ava \"{src,test}/**/*.spec.js\"",
"start": "node bin/client",
"dev": "node t.js",
"demo": "node example/ding-dong-bot.js"
},
"repository": {
......
......@@ -108,9 +108,9 @@ class Bridge {
/**
* Do not insert `return` in front of the code.
* because the new line `\n` will cause return nothing at all
* because the new line `\n` will cause return nothing at all
*/
return 'rejectioReturnValue = '
return 'rejectioReturnValue = '
+ fs.readFileSync(
path.join(__dirname, 'wechaty-bro.js')
, 'utf8'
......@@ -143,6 +143,38 @@ class Bridge {
})
}
roomFind(filterFunction) {
return this.proxyWechaty('roomFind', filterFunction)
.catch(e => {
log.error('PuppetWebBridge', 'roomFind() exception: %s', e.message)
throw e
})
}
roomDelMember(roomId, contactId) {
return this.proxyWechaty('roomDelMember', roomId, contactId)
.catch(e => {
log.error('PuppetWebBridge', 'roomDelMember(%s, %s) exception: %s', roomId, contactId, e.message)
throw e
})
}
roomAddMember(roomId, contactId) {
return this.proxyWechaty('roomAddMember', roomId, contactId)
.catch(e => {
log.error('PuppetWebBridge', 'roomAddMember(%s, %s) exception: %s', roomId, contactId, e.message)
throw e
})
}
roomCreate(contactIdList) {
return this.proxyWechaty('roomCreate', contactIdList)
.catch(e => {
log.error('PuppetWebBridge', 'roomCreate(%s) exception: %s', contactIdList, e.message)
throw e
})
}
send(toUserName, content) {
return this.proxyWechaty('send', toUserName, content)
.catch(e => {
......
......@@ -33,7 +33,7 @@ class Browser extends EventEmitter {
this.sessionFile = sessionFile // a file to save session cookies
// this.live = false
this.targetState('close')
this.currentState('close')
}
......@@ -79,9 +79,9 @@ class Browser extends EventEmitter {
/**
* XXX
*
*
* when open url, there could happen a quit() call.
* should check here: if we are in `close` target state, we should clean up
* should check here: if we are in `close` target state, we should clean up
*/
if (this.targetState() === 'open') {
this.currentState('open')
......@@ -174,7 +174,7 @@ class Browser extends EventEmitter {
.withCapabilities(customChrome)
.build()
}
getPhantomJsDriver() {
// setup custom phantomJS capability https://github.com/SeleniumHQ/selenium/issues/2069
const phantomjsExe = require('phantomjs-prebuilt').path
......@@ -187,9 +187,9 @@ class Browser extends EventEmitter {
, '--ssl-protocol=any' // http://stackoverflow.com/a/26503588/1123955
//, '--ssl-protocol=TLSv1' // https://github.com/ariya/phantomjs/issues/11239#issuecomment-42362211
// issue: Secure WebSocket(wss) do not work with Self Signed Certificate in PhantomJS #12
// issue: Secure WebSocket(wss) do not work with Self Signed Certificate in PhantomJS #12
// , '--ssl-certificates-path=D:\\cygwin64\\home\\zixia\\git\\wechaty' // http://stackoverflow.com/a/32690349/1123955
// , '--ssl-client-certificate-file=cert.pem' //
// , '--ssl-client-certificate-file=cert.pem' //
]
if (process.env.WECHATY_DEBUG) {
......@@ -215,7 +215,7 @@ class Browser extends EventEmitter {
const driver = new WebDriver.Builder()
.withCapabilities(customPhantom)
.build()
/**
* FIXME: ISSUE #21 - https://github.com/zixia/wechaty/issues/21
*
......@@ -237,7 +237,7 @@ this.onResourceRequested = function(request, net) {
// https://github.com/detro/ghostdriver/blob/f976007a431e634a3ca981eea743a2686ebed38e/src/session.js#L233
// driver.manage().timeouts().pageLoadTimeout(2000)
return driver
}
......@@ -270,10 +270,10 @@ this.onResourceRequested = function(request, net) {
log.silly('PuppetWebBrowser', 'quit() this.driver = null')
/**
*
* if we use AVA to test, then this.clean will cause problems
*
* if we use AVA to test, then this.clean will cause problems
* because there will be more than one instance of browser with the same nodejs process id
*
*
*/
yield this.clean()
......@@ -335,7 +335,7 @@ this.onResourceRequested = function(request, net) {
getBrowserPids() {
log.silly('PuppetWebBrowser', 'getBrowserPids()')
return new Promise((resolve, reject) => {
require('ps-tree')(process.pid, (err, children) => {
if (err) {
......@@ -415,6 +415,11 @@ this.onResourceRequested = function(request, net) {
// log.verbose('PuppetWebBrowser', `Browser.execute() driver.getSession: %s`, util.inspect(this.driver.getSession()))
if (this.dead()) { return Promise.reject(new Error('browser dead')) }
// XXX
console.log('#############')
console.log(script)
console.log(args)
return this.driver.executeScript.apply(this.driver, arguments)
.catch(e => {
// this.dead(e)
......@@ -478,7 +483,7 @@ this.onResourceRequested = function(request, net) {
// this.live = false
this.currentState('closing')
this.quit().then(_ => this.currentState('close'))
// must use nextTick here, or promise will hang... 2016/6/10
process.nextTick(_ => {
log.verbose('PuppetWebBrowser', 'dead() emit a `dead` event because %s', errMsg)
......@@ -548,7 +553,7 @@ this.onResourceRequested = function(request, net) {
else { return true }
})
}
return new Promise((resolve, reject) => {
this.driver.manage().getCookies()
.then(cookieFilter)
......
......@@ -204,7 +204,7 @@ class PuppetWeb extends Puppet {
log.warn('PuppetWeb', 'initBridge() found targetState != live, no init anymore')
return Promise.resolve('skipped')
}
return bridge.init()
.catch(e => {
if (!this.browser){
......@@ -229,9 +229,9 @@ class PuppetWeb extends Puppet {
/**
* @depreciated 20160825 zixia
*
*
* when `unload` there should always be a `disconnect` event?
*/
*/
// server.on('unload' , Event.onServerUnload.bind(this))
server.on('connection', Event.onServerConnection.bind(this))
......@@ -322,7 +322,7 @@ class PuppetWeb extends Puppet {
if (!this.bridge) {
throw new Error('PuppetWeb has no bridge for getContact()')
}
return this.bridge.getContact(id)
.catch(e => {
log.error('PuppetWeb', 'getContact(%d) exception: %s', id, e.message)
......@@ -340,6 +340,64 @@ class PuppetWeb extends Puppet {
throw e
})
}
roomFind(filterFunction) {
if (!this.bridge) {
return Promise.reject(new Error('findRoom fail: no bridge(yet)!'))
}
return this.bridge.roomFind(filterFunction)
.catch(e => {
log.warn('PuppetWeb', 'roomFind(%s) rejected: %s', filterFunction, e.message)
throw e
})
}
roomDelMember(room, contact) {
if (!this.bridge) {
return Promise.reject(new Error('roomDelMember fail: no bridge(yet)!'))
}
const roomId = room.get('id')
const contactId = contact.get('id')
return this.bridge.roomDelMember(roomId, contactId)
.catch(e => {
log.warn('PuppetWeb', 'roomDelMember(%s) rejected: %s', contact, e.message)
throw e
})
}
roomAddMember(room, contact) {
if (!this.bridge) {
return Promise.reject(new Error('fail: no bridge(yet)!'))
}
const roomId = room.get('id')
const contactId = contact.get('id')
return this.bridge.roomAddMember(roomId, contactId)
.catch(e => {
log.warn('PuppetWeb', 'roomAddMember(%s) rejected: %s', contact, e.message)
throw e
})
}
roomCreate(contactList) {
if (!this.bridge) {
return Promise.reject(new Error('fail: no bridge(yet)!'))
}
if (!contactList || ! typeof contactList === 'array') {
throw new Error('contactList not found')
}
const contactIdList = contactList.map(c => c.get('id'))
return this.bridge.roomCreate(contactIdList)
.catch(e => {
log.warn('PuppetWeb', 'roomCreate(%s) rejected: %s', contact, e.message)
throw e
})
}
}
module.exports = PuppetWeb.default = PuppetWeb.PuppetWeb = PuppetWeb
......@@ -29,87 +29,6 @@
/*global angular*/
(function(port) {
port = port || 8788
/*
* WechatyBro injectio must return this object.
* PuppetWebBridge need this to decide if injection is successful.
*/
var retObj = {
code: 200 // 2XX ok, 4XX/5XX error. HTTP like
, message: 'any message'
, port: port
}
if (typeof this.WechatyBro !== 'undefined') {
retObj.code = 201
retObj.message = 'WechatyBro already injected?'
return retObj
}
var WechatyBro = {
glue: {
// will be initialized by glueToAngular() function
}
// glue funcs
// , getLoginStatusCode: function() { return WechatyBro.glue.loginScope.code }
// , getLoginQrImgUrl: function() { return WechatyBro.glue.loginScope.qrcodeUrl }
, angularIsReady: angularIsReady
// variable
, vars: {
loginStatus: false
, initStatus: false
, socket: null
, eventsBuf: []
, scanCode: null
, heartBeatTimmer: null
}
// funcs
, init: init // initialize WechatyBro @ Browser
, send: send // send message to wechat user
, clog: clog // log to Console
, slog: slog // log to SocketIO
, log: log // log to both Console & SocketIO
, ding: ding // simple return 'dong'
, quit: quit // quit wechat
, emit: emit // send event to server
, logout: logout // logout current logined user
, getContact: getContact
, getUserName: getUserName
, getMsgImg: getMsgImg
// test purpose
, isLogin: isLogin
, initClog: initClog
}
this.WechatyBro = WechatyBro
retObj.code = 200
retObj.message = 'WechatyBro Inject Succ'
return retObj
/**
* Two return mode of WebDriver (should be one of them at a time)
* 1. a callback. return a value by call callback with args
* 2. direct return
*/
// var callback = arguments[arguments.length - 1]
// if (typeof callback === 'function') {
// return callback(retObj)
// } else {
// return retObj
// }
retObj.code = 500
retObj.message = 'SHOULD NOT RUN TO HERE'
return retObj
/////////////////////////////////////////////////////////////////////////////
function init() {
if (!angularIsReady()) {
......@@ -273,12 +192,14 @@
var accountFactory = injector.get('accountFactory')
var appFactory = injector.get('appFactory')
var chatroomFactory = injector.get('chatroomFactory')
var chatFactory = injector.get('chatFactory')
var contactFactory = injector.get('contactFactory')
var confFactory = injector.get('confFactory')
var loginFactory = injector.get('loginFactory')
var http = injector.get('$http')
var state = injector.get('$state')
var mmHttp = injector.get('mmHttp')
var appScope = angular.element('[ng-controller="appController"]').scope()
......@@ -323,8 +244,10 @@
WechatyBro.glue = {
injector: injector
, http: http
, state
, accountFactory: accountFactory
, chatroomFactory
, chatFactory: chatFactory
, confFactory: confFactory
, contactFactory: contactFactory
......@@ -528,4 +451,136 @@
: null
}
function roomFind(filterFunction) {
var contactFactory = WechatyBro.glue.contactFactory
var match
if (!filterFunction) {
match = function() { return true }
} else {
match = eval(filterFunction)
}
// log(match.toString())
return contactFactory.getAllChatroomContact()
.filter(r => match(r.NickName))
.map(r => r.UserName)
}
function roomDelMember(ChatRoomName, UserName) {
const chatroomFactory = WechatyBro.glue.chatroomFactory
return chatroomFactory.delMember(ChatRoomName, UserName)
}
function roomAddMember(ChatRoomName, UserName) {
const chatroomFactory = WechatyBro.glue.chatroomFactory
// XXX
log(ChatRoomName)
log(UserName)
return chatroomFactory.addMember(ChatRoomName, UserName)
}
function roomCreate(UserNameList) {
const UserNameListArg = UserNameList.map(n => { return { UserName: n } })
const chatroomFactory = WechatyBro.glue.chatroomFactory
chatroomFactory.create(UserNameListArg)
.then(r => {
if (r.BaseResponse && 0 == r.BaseResponse.Ret || -2013 == e.BaseResponse.Ret) {
// be careful: key name is userName, not UserName! 20161001
WechatyBro.glue.state.go('chat', { userName: r.ChatRoomName })
}
})
.catch(e => {
// TBD
console.log(e)
})
return 'no callback (yet)'
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
port = port || 8788
/*
* WechatyBro injectio must return this object.
* PuppetWebBridge need this to decide if injection is successful.
*/
var retObj = {
code: 200 // 2XX ok, 4XX/5XX error. HTTP like
, message: 'any message'
, port: port
}
if (typeof this.WechatyBro !== 'undefined') {
retObj.code = 201
retObj.message = 'WechatyBro already injected?'
return retObj
}
var WechatyBro = {
glue: {
// will be initialized by glueToAngular() function
}
// glue funcs
// , getLoginStatusCode: function() { return WechatyBro.glue.loginScope.code }
// , getLoginQrImgUrl: function() { return WechatyBro.glue.loginScope.qrcodeUrl }
, angularIsReady: angularIsReady
// variable
, vars: {
loginStatus: false
, initStatus: false
, socket: null
, eventsBuf: []
, scanCode: null
, heartBeatTimmer: null
}
// funcs
, init: init // initialize WechatyBro @ Browser
, send: send // send message to wechat user
, clog: clog // log to Console
, slog: slog // log to SocketIO
, log: log // log to both Console & SocketIO
, ding: ding // simple return 'dong'
, quit: quit // quit wechat
, emit: emit // send event to server
, logout: logout // logout current logined user
, getContact: getContact
, getUserName: getUserName
, getMsgImg: getMsgImg
, roomFind
, roomCreate
, roomAddMember
, roomDelMember
// test purpose
, isLogin: isLogin
, initClog: initClog
}
this.WechatyBro = WechatyBro
retObj.code = 200
retObj.message = 'WechatyBro Inject Succ'
/**
* Two return mode of WebDriver (should be one of them at a time)
* 1. a callback. return a value by call callback with args
* 2. direct return
*/
var callback = arguments[arguments.length - 1]
if (typeof callback === 'function') {
return callback(retObj)
}
return retObj
// retObj.code = 500
// retObj.message = 'SHOULD NOT RUN TO HERE'
// return retObj
}.apply(window, arguments))
......@@ -22,15 +22,25 @@ class Room {
toString() { return this.id }
toStringEx() { return `Room(${this.obj.name}[${this.id}])` }
isReady() {
return this.obj.members && this.obj.members.length
}
refresh() {
this.obj = {}
return this.ready()
}
ready(contactGetter) {
log.silly('Room', 'ready(%s)', contactGetter ? contactGetter.constructor.name : '')
if (!this.id) {
log.warn('Room', 'ready() on a un-inited Room')
return Promise.resolve(this)
} else if (this.obj.members && this.obj.members.length) {
const e = new Error('ready() on a un-inited Room')
log.warn('Room', e.message)
return Promise.reject(e)
} else if (this.isReady()) {
return Promise.resolve(this)
} else if (this.obj.id) {
log.warn('Room', 'ready() ready but members list empty in room %s. reloading', this.obj.name)
log.warn('Room', 'ready() has obj.id but members list empty in room %s. reloading', this.obj.name)
}
contactGetter = contactGetter || Room.puppet.getContact.bind(Room.puppet)
......@@ -50,7 +60,10 @@ class Room {
get(prop) { return this.obj[prop] }
parse(rawObj) {
return !rawObj ? {} : {
if (!rawObj) {
return {}
}
return {
id: rawObj.UserName
, encryId: rawObj.EncryChatRoomId // ???
, name: rawObj.NickName
......@@ -79,33 +92,132 @@ class Room {
Object.keys(this.obj).forEach(k => console.error(`${k}: ${this.obj[k]}`))
}
static find() {
return new Room('-1')
del(contact) {
log.verbose('Room', 'del(%s) from %s', contact, this)
if (!contact) {
throw new Error('contact not found')
}
return Room.puppet.roomDelMember(this, contact)
}
static findAll() {
return [
new Room('-2')
, new Room('-3')
]
quit() {
throw new Error('wx web not implement yet')
// WechatyBro.glue.chatroomFactory.quit("@@1c066dfcab4ef467cd0a8da8bec90880035aa46526c44f504a83172a9086a5f7"
}
}
Room.init = function() { Room.pool = {} }
Room.init()
Room.load = function(id) {
if (!id) { return null }
add(contact) {
log.verbose('Room', 'add(%s) to %s', contact, this)
if (!contact) {
throw new Error('contact not found')
}
if (id in Room.pool) {
return Room.pool[id]
return Room.puppet.roomAddMember(this, contact)
}
return Room.pool[id] = new Room(id)
}
Room.attach = function(puppet) {
// if (!puppet) {
// throw new Error('Room.attach got no puppet to attach!')
// }
Room.puppet = puppet
static create(contactList) {
log.verbose('Room', 'create(%s)', contactList.join(','))
if (!contactList || ! typeof contactList === 'array') {
throw new Error('contactList not found')
}
return Room.puppet.roomCreate(contactList)
}
// private
static _find({
name
}) {
log.silly('Room', '_find(%s)', name)
if (!name) {
throw new Error('name not found')
}
let filterFunction
if (name instanceof RegExp) {
filterFunction = `c => ${name.toString()}.test(c)`
} else if (typeof name === 'string') {
filterFunction = `c => c === ${name}`
} else {
throw new Error('unsupport name type')
}
return Room.puppet.roomFind(filterFunction)
.then(idList => {
return idList
})
.catch(e => {
log.error('Room', '_find() rejected: %s', e.message)
throw e
})
}
static find({
name
}) {
log.verbose('Room', 'find(%s)', name)
return Room._find({name})
.then(idList => {
if (!idList || !Array.isArray(idList)){
throw new Error('_find return error')
}
if (idList.length < 1) {
return null
}
const id = idList[0]
return Room.load(id)
})
.catch(e => {
log.error('Room', 'find() rejected: %s', e.message)
return [] // fail safe
})
}
static findAll({
name
}) {
log.verbose('Room', 'findAll(%s)', name)
return Room._find({name})
.then(idList => {
// console.log(idList)
if (!idList || !Array.isArray(idList)){
throw new Error('_find return error')
}
if (idList.length < 1) {
return []
}
return idList.map(i => Room.load(i))
})
.catch(e => {
log.error('Room', 'findAll() rejected: %s', e.message)
throw e
})
}
static init() { Room.pool = {} }
static load(id) {
if (!id) { return null }
if (id in Room.pool) {
return Room.pool[id]
}
return Room.pool[id] = new Room(id)
}
static attach(puppet) {
// if (!puppet) {
// throw new Error('Room.attach got no puppet to attach!')
// }
Room.puppet = puppet
}
}
Room.init()
module.exports = Room
......@@ -9,14 +9,6 @@ import {
Room.attach(new Puppet())
// const test = require('tape')
// const Message = require('../src/message')
// const Room = require('../src/room')
// const Contact = require('../src/contact')
// const Puppet = require('../src/puppet')
// const log = require('../src/brolog-env')
test('Room smoke testing', async t => {
const UserName = '@0bb3e4dd746fdbd4a80546aef66f4085'
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册