util-lib.ts 5.5 KB
Newer Older
1
import * as http from 'http'
2 3

import log from './brolog-env'
4

5 6 7 8
/**
 * bug compatible with:
 * https://github.com/wechaty/wechaty/issues/40#issuecomment-252802084
 */
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
9
// import * as ws from 'ws'
10

11
class UtilLib {
12 13 14 15 16
  public static stripHtml(html?: string): string {
    if (!html) {
      return ''
    }
    return html.replace(/(<([^>]+)>)/ig, '')
17
  }
18

19 20 21 22 23
  public static unescapeHtml(str?: string): string {
    if (!str) {
      return ''
    }
    return str
24 25 26 27 28 29
    .replace(/&apos;/g, "'")
    .replace(/&quot;/g, '"')
    .replace(/&gt;/g, '>')
    .replace(/&lt;/g, '<')
    .replace(/&amp;/g, '&')
  }
30

31 32 33 34 35
  public static digestEmoji(html?: string): string {
    if (!html) {
      return ''
    }
    return html
36 37 38 39 40 41 42
          .replace(/<img class="(\w*?emoji) (\w*?emoji[^"]+?)" text="(.*?)_web" src=[^>]+>/g
                 , '$3'
                 ) // <img class="emoji emoji1f4a4" text="[流汗]_web" src="/zh_CN/htmledition/v2/images/spacer.gif" />
          .replace(/<span class="(\w*?emoji) (\w*?emoji[^"]+?)"><\/span>/g
                 , '[$2]'
                 ) // '<span class="emoji emoji1f334"></span>'
  }
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
  /**
   * unifyEmoji: the same emoji will be encoded as different xml code in browser. unify them.
   *
   *  from: <img class="emoji emoji1f602" text="_web" src="/zh_CN/htmledition/v2/images/spacer.gif" />
   *  to:   <span class=\"emoji emoji1f602\"></span>
   *
   */
  public static unifyEmoji(html?: string): string {
    if (!html) {
      return ''
    }
    return html
          .replace(/<img class="(\w*?emoji) (\w*?emoji[^"]+?)" text="(.*?)_web" src=[^>]+>/g
                 , '<emoji code="$2"/>'
                 ) // <img class="emoji emoji1f4a4" text="[流汗]_web" src="/zh_CN/htmledition/v2/images/spacer.gif" />
          .replace(/<span class="(\w*?emoji) (\w*?emoji[^"]+?)"><\/span>/g
                 , '<emoji code="$2"/>'
                 ) // '<span class="emoji emoji1f334"></span>'
  }

  public static plainText(html?: string): string {
    if (!html) {
      return ''
    }
68 69 70 71 72 73
    return UtilLib.stripHtml(
      UtilLib.unescapeHtml(
        UtilLib.stripHtml(
          UtilLib.digestEmoji(
            html
          )
74 75 76 77 78
        )
      )
    )
  }

79
  public static  downloadStream(url: string, cookies: any[]): Promise<NodeJS.ReadableStream> {
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
    // const myurl = 'http://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetmsgimg?&MsgID=3080011908135131569&skey=%40crypt_c117402d_53a58f8fbb21978167a3fc7d3be7f8c9'
    url = url.replace(/^https/i, 'http') // use http for better performance
    const options = require('url').parse(url)

    options.headers = {
      Accept: 'image/webp,image/*,*/*;q=0.8'
      , 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'
      , Referer: 'https://wx.qq.com/'
      , 'Accept-Encoding': 'gzip, deflate, sdch'
      , 'Accept-Language': 'zh-CN,zh;q=0.8'
    }
    options.agent = http.globalAgent

    /**
     * 'pgv_pvi=6639183872; pgv_si=s8359147520;
     * webwxuvid=747895d9dac5a25dd3a78175a5e931d879e026cacaf3ac06de0bd5f0714 ... ;
     * mm_lang=zh_CN; MM_WX_NOTIFY_STATE=1; MM_WX_SOUND_STATE=1; wxloadtime=1465928826_expired;
     * wxpluginkey=1465901102; wxuin=1211516682; wxsid=zMT7Gb24aTQzB1rA;
     * webwx_data_ticket=gSeBbuhX+0kFdkXbgeQwr6Ck'
     */
100
    options.headers.Cookie = cookies.map(c => `${c['name']}=${c['value']}`).join('; ')
101 102 103 104 105 106 107 108 109 110 111 112 113 114
    // log.verbose('Util', 'Cookie: %s', options.headers.Cookie)

    return new Promise((resolve, reject) => {
      const req = http.request(options, (res) => {
        // console.log(`STATUS: ${res.statusCode}`);
        // console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
        // res.setEncoding('utf8');
        resolve(res)
      })

      req.on('error', (e) => {
        log.warn('WebUtil', `downloadStream() problem with request: ${e.message}`)
      })
      req.end()
115
    })
116
  }
117

118
  // credit - http://stackoverflow.com/a/2117523/1123955
119
  public static guid(): string {
120 121 122 123 124 125
    /* tslint:disable:no-bitwise */
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
      const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8)
      return v.toString(16)
    })
  }
126

127 128 129 130 131 132 133 134 135 136 137
  /**
   *
   * @param port is just a suggestion.
   * there's no grantuee for the number
   *
   * The IANA suggested ephemeral port range.
   * @see http://en.wikipedia.org/wiki/Ephemeral_ports
   *
   * const DEFAULT_IANA_RANGE = {min: 49152, max: 65535}
   *
   */
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
138
  public static getPort(port: number): Promise<number> {
139 140 141 142 143 144 145 146 147 148 149
    log.verbose('UtilLib', 'getPort(%d)', port)
    let tryPort = nextPort(port || 38788)

    return new Promise((resolve, reject) => {
      // https://gist.github.com/mikeal/1840641
      function _getPort(cb) {
        const server = require('net').createServer()
        server.on('error', function(err) {
          if (err) {/* fail safe */ }
          tryPort = nextPort(port)
          _getPort(cb)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
150
        })
151 152 153 154 155 156 157 158 159 160 161 162
        server.listen(tryPort, function(err) {
          if (err) {/* fail safe */}
          server.once('close', function() {
            cb(tryPort)
          })
          server.close()
        })
      }
      _getPort(okPort => {
        log.verbose('UtilLib', 'getPort(%d) return: %d'
                  , port
                  , okPort
163
        )
164 165
        resolve(okPort)
      })
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
166
    })
167

168
    function nextPort(newPort: number): number {
169 170 171 172
      const RANDOM_RANGE = 1024
      const n = Math.floor(Math.random() * RANDOM_RANGE)
      return newPort + n
    }
173
  }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
174 175
}

176 177 178
// module.exports = UtilLib.default = UtilLib.UtilLib = UtilLib

export default UtilLib