mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-02-03 07:40:05 +08:00
351 lines
11 KiB
VimL
351 lines
11 KiB
VimL
"=============================================================================
|
|
" gitter.vim --- a gitter client
|
|
" Copyright (c) 2016-2023 Wang Shidong & Contributors
|
|
" Author: Wang Shidong < wsdjeg@outlook.com >
|
|
" URL: https://spacevim.org
|
|
" License: GPLv3
|
|
"=============================================================================
|
|
|
|
if exists('s:room_jobs')
|
|
finish
|
|
endif
|
|
|
|
|
|
let s:JOB = SpaceVim#api#import('job')
|
|
let s:JSON = SpaceVim#api#import('data#json')
|
|
let s:LOG = SpaceVim#logger#derive('gitter')
|
|
|
|
" the win 11 curl in system32/ directory do not support unicode, use
|
|
" neovim's curl
|
|
if has('nvim') && exists('v:progpath') && (has('win64') || has('win32'))
|
|
let s:curl = fnamemodify(v:progpath, ':h') . '\curl.exe'
|
|
else
|
|
let s:curl = 'curl'
|
|
endif
|
|
|
|
let g:chat_gitter_token = get(g:, 'chat_gitter_token', '')
|
|
|
|
let s:room_jobs = {}
|
|
function! chat#gitter#enter_room(room) abort
|
|
let roomid = s:room_to_roomid(a:room)
|
|
if empty(roomid)
|
|
return 0
|
|
endif
|
|
if !has_key(s:fetch_response, a:room)
|
|
call s:fetch(roomid)
|
|
endif
|
|
if !has_key(s:room_jobs, a:room)
|
|
let cmd = [s:curl, '-s', '--show-error', '--fail', '-N',
|
|
\ '-H', 'Accept: application/json',
|
|
\ '-H', printf('Authorization: Bearer %s', g:chat_gitter_token),
|
|
\ printf('https://stream.gitter.im/v1/rooms/%s/chatMessages', roomid)
|
|
\ ]
|
|
let s:room_jobs[a:room] = s:JOB.start(cmd, {
|
|
\ 'on_stdout' : function('s:gitter_stream_stdout'),
|
|
\ 'on_stderr' : function('s:gitter_stream_stderr'),
|
|
\ 'on_exit' : function('s:gitter_stream_exit'),
|
|
\ })
|
|
call chat#windows#push({
|
|
\ 'user' : '--->',
|
|
\ 'username' : '--->',
|
|
\ 'room' : a:room,
|
|
\ 'msg' : 'connected to channel!',
|
|
\ 'time': strftime("%Y-%m-%d %H:%M"),
|
|
\ })
|
|
endif
|
|
return 1
|
|
endfunction
|
|
|
|
function! s:room_to_roomid(room) abort
|
|
let room = filter(deepcopy(s:channels), 'has_key(v:val, "uri") && v:val.uri ==# a:room')
|
|
if !empty(room)
|
|
return room[0].id
|
|
else
|
|
return ''
|
|
endif
|
|
endfunction
|
|
|
|
function! s:roomid_to_room(roomid) abort
|
|
let room = filter(deepcopy(s:channels), 'has_key(v:val, "id") && has_key(v:val, "uri") && v:val.id ==# a:roomid')
|
|
if !empty(room)
|
|
return room[0].uri
|
|
else
|
|
return ''
|
|
endif
|
|
endfunction
|
|
|
|
|
|
function! s:gitter_stream_stdout(id, data, event) abort
|
|
for line in a:data
|
|
if line !~# '^\s*$'
|
|
call s:LOG.debug('gitter_stream_stdout :' . line)
|
|
endif
|
|
endfor
|
|
for room in keys(s:room_jobs)
|
|
if s:room_jobs[room] ==# a:id
|
|
let message = join(a:data, '')
|
|
if message =~# '^\s*$'
|
|
" skip empty string or space
|
|
return
|
|
endif
|
|
let msg = s:JSON.json_decode(message)
|
|
call chat#windows#push({
|
|
\ 'user' : msg.fromUser.displayName,
|
|
\ 'username' : msg.fromUser.username,
|
|
\ 'room' : room,
|
|
\ 'msg' : msg.text,
|
|
\ 'time': s:format_time(msg.sent),
|
|
\ })
|
|
if !chat#windows#is_opened()
|
|
\ && s:enable_notify(room)
|
|
call chat#notify#noti(msg.fromUser.displayName . ': ' . msg.text)
|
|
endif
|
|
return
|
|
endif
|
|
endfor
|
|
endfunction
|
|
|
|
function! s:enable_notify(room) abort
|
|
let room = filter(deepcopy(s:channels), 'has_key(v:val, "uri") && v:val.uri ==# a:room && has_key(v:val, "lurk")')
|
|
if !empty(room)
|
|
return room[0].lurk
|
|
else
|
|
return 0
|
|
endif
|
|
endfunction
|
|
|
|
function! s:format_time(t) abort
|
|
return matchstr(a:t, '\d\d\d\d-\d\d-\d\d') . ' ' . matchstr(a:t, '\d\d:\d\d')
|
|
endfunction
|
|
|
|
function! s:gitter_stream_stderr(id, data, event) abort
|
|
for line in a:data
|
|
call s:LOG.debug('gitter_stream_stderr :' . line)
|
|
endfor
|
|
|
|
endfunction
|
|
|
|
function! s:gitter_stream_exit(id, data, event) abort
|
|
call s:LOG.debug('gitter_stream_exit :' . a:data)
|
|
for room in keys(s:room_jobs)
|
|
if s:room_jobs[room] ==# a:id
|
|
call chat#windows#push({
|
|
\ 'user' : '--->',
|
|
\ 'username' : '--->',
|
|
\ 'room' : room,
|
|
\ 'msg' : 'The channel is disconnected.',
|
|
\ 'time': strftime("%Y-%m-%d %H:%M"),
|
|
\ })
|
|
if !chat#windows#is_opened()
|
|
\ && s:enable_notify(room)
|
|
call chat#notify#noti('The ' . room . ' channel is disconnected.')
|
|
endif
|
|
unlet s:room_jobs[room]
|
|
return
|
|
endif
|
|
endfor
|
|
endfunction
|
|
|
|
let s:fetch_response = {}
|
|
function! s:fetch(roomid) abort
|
|
let room = s:roomid_to_room(a:roomid)
|
|
if !has_key(s:fetch_response, room)
|
|
let cmd = [s:curl, '-s', '--show-error', '--fail',
|
|
\ '-H', 'Accept: application/json',
|
|
\ '-H', printf('Authorization: Bearer %s', g:chat_gitter_token),
|
|
\ printf('https://api.gitter.im/v1/rooms/%s/chatMessages?limit=50', a:roomid)
|
|
\ ]
|
|
let s:fetch_response[room] = {
|
|
\ 'stdout' : [],
|
|
\ 'stderr' : [],
|
|
\ 'jobid' : s:JOB.start(cmd,
|
|
\ {
|
|
\ 'on_stdout' : function('s:gitter_fetch_stdout'),
|
|
\ 'on_stderr' : function('s:gitter_fetch_stderr'),
|
|
\ 'on_exit' : function('s:gitter_fetch_exit'),
|
|
\ })
|
|
\ }
|
|
call chat#windows#push({
|
|
\ 'user' : '--->',
|
|
\ 'username' : '--->',
|
|
\ 'room' : room,
|
|
\ 'msg' : 'fetching channel messages',
|
|
\ 'time': strftime("%Y-%m-%d %H:%M"),
|
|
\ })
|
|
endif
|
|
endfunction
|
|
|
|
function! s:gitter_fetch_stdout(id, data, event) abort
|
|
for line in a:data
|
|
call s:LOG.debug('fetch_stdout :' . line)
|
|
endfor
|
|
call s:LOG.debug('s:fetch_response keys :' . string(keys(s:fetch_response)))
|
|
for room in keys(s:fetch_response)
|
|
if s:fetch_response[room].jobid ==# a:id
|
|
let s:fetch_response[room].stdout += a:data
|
|
break
|
|
endif
|
|
endfor
|
|
endfunction
|
|
|
|
function! s:gitter_fetch_stderr(id, data, event) abort
|
|
for line in a:data
|
|
call s:LOG.debug('fetch_stderr :' . line)
|
|
endfor
|
|
for room in keys(s:fetch_response)
|
|
if s:fetch_response[room].jobid ==# a:id
|
|
let s:fetch_response[room].stderr += a:data
|
|
break
|
|
endif
|
|
endfor
|
|
endfunction
|
|
|
|
function! s:gitter_fetch_exit(id, data, event) abort
|
|
call s:LOG.debug('fetch job exit code :' . a:data)
|
|
for room in keys(s:fetch_response)
|
|
if s:fetch_response[room].jobid ==# a:id
|
|
if !empty(s:fetch_response[room].stdout)
|
|
let messages = s:JSON.json_decode(join(s:fetch_response[room].stdout, ''))
|
|
let msgs = []
|
|
for msg in messages
|
|
call add(msgs, {
|
|
\ 'user' : msg.fromUser.displayName,
|
|
\ 'username' : msg.fromUser.username,
|
|
\ 'room' : room,
|
|
\ 'msg' : msg.text,
|
|
\ 'replyCounts' : get(msg, 'threadMessageCount', 0),
|
|
\ 'time': s:format_time(msg.sent),
|
|
\ })
|
|
endfor
|
|
call chat#windows#push(msgs)
|
|
call chat#windows#push({
|
|
\ 'user' : '--->',
|
|
\ 'username' : '--->',
|
|
\ 'room' : room,
|
|
\ 'msg' : 'fetch channel message done!',
|
|
\ 'time': strftime("%Y-%m-%d %H:%M"),
|
|
\ })
|
|
return
|
|
else
|
|
call chat#windows#push({
|
|
\ 'user' : '--->',
|
|
\ 'username' : '--->',
|
|
\ 'room' : room,
|
|
\ 'msg' : 'failed to fetch message.',
|
|
\ 'time': strftime("%Y-%m-%d %H:%M"),
|
|
\ })
|
|
unlet s:fetch_response[room]
|
|
endif
|
|
return
|
|
endif
|
|
endfor
|
|
endfunction
|
|
|
|
let s:channels = []
|
|
function! chat#gitter#get_channels() abort
|
|
if empty(s:channels)
|
|
call s:get_all_channels()
|
|
return []
|
|
else
|
|
let rooms = filter(deepcopy(s:channels), 'has_key(v:val, "uri")')
|
|
return map(rooms, 'v:val.uri')
|
|
endif
|
|
endfunction
|
|
|
|
|
|
let s:list_all_channels_jobid = -1
|
|
let s:list_all_channels_stdout = []
|
|
let s:list_all_channels_stderr = []
|
|
function! s:get_all_channels() abort
|
|
if s:list_all_channels_jobid <= 0
|
|
call chat#windows#push({
|
|
\ 'user' : '--->',
|
|
\ 'username' : '--->',
|
|
\ 'room' : '',
|
|
\ 'protocol' : 'gitter',
|
|
\ 'msg' : 'listing gitter channels',
|
|
\ 'time': strftime("%Y-%m-%d %H:%M"),
|
|
\ })
|
|
let cmd = [s:curl, '-s', '--show-error', '--fail',
|
|
\ '-H', 'Accept: application/json',
|
|
\ '-H', printf('Authorization: Bearer %s', g:chat_gitter_token),
|
|
\ 'https://api.gitter.im/v1/rooms',
|
|
\ ]
|
|
let s:list_all_channels_jobid = s:JOB.start(cmd, {
|
|
\ 'on_stdout' : function('s:get_all_channels_stdout'),
|
|
\ 'on_stderr' : function('s:get_all_channels_stderr'),
|
|
\ 'on_exit' : function('s:get_all_channels_exit'),
|
|
\ })
|
|
endif
|
|
endfunction
|
|
|
|
function! s:get_all_channels_stdout(id, data, event) abort
|
|
for line in a:data
|
|
call s:LOG.debug('get_all_channels_stdout: ' . line)
|
|
endfor
|
|
let s:list_all_channels_stdout = s:list_all_channels_stdout + a:data
|
|
endfunction
|
|
function! s:get_all_channels_stderr(id, data, event) abort
|
|
for line in a:data
|
|
call s:LOG.debug('get_all_channels_stderr: ' . line)
|
|
endfor
|
|
let s:list_all_channels_stderr = s:list_all_channels_stderr + a:data
|
|
endfunction
|
|
" I am not sure if this is a bug. sometimes the exit data is 0, but there no
|
|
" stdout, all responses are sent to stderr.
|
|
function! s:get_all_channels_exit(id, data, event) abort
|
|
call s:LOG.debug('get_all_channels_exit code: ' . a:data)
|
|
if a:data ==# 0 && !empty(s:list_all_channels_stdout)
|
|
let s:channels = s:JSON.json_decode(join(s:list_all_channels_stdout, ''))
|
|
call chat#windows#push({
|
|
\ 'user' : '--->',
|
|
\ 'username' : '--->',
|
|
\ 'room' : '',
|
|
\ 'protocol' : 'gitter',
|
|
\ 'msg' : 'list channels done!',
|
|
\ 'time': strftime("%Y-%m-%d %H:%M"),
|
|
\ })
|
|
if !chat#windows#is_opened()
|
|
call chat#notify#noti('gitter protocol channels updated!')
|
|
endif
|
|
else
|
|
call chat#windows#push({
|
|
\ 'user' : '--->',
|
|
\ 'username' : '--->',
|
|
\ 'room' : '',
|
|
\ 'protocol' : 'gitter',
|
|
\ 'msg' : 'failed to list channels of gitter protocol!',
|
|
\ 'time': strftime("%Y-%m-%d %H:%M"),
|
|
\ })
|
|
if !chat#windows#is_opened()
|
|
call chat#notify#noti('failed to list channels of gitter protocol!')
|
|
endif
|
|
let s:list_all_channels_jobid = -1
|
|
endif
|
|
endfunction
|
|
|
|
function! Test(str) abort
|
|
exe a:str
|
|
endfunction
|
|
|
|
function! chat#gitter#send(room, msg) abort
|
|
let roomid = s:room_to_roomid(a:room)
|
|
let cmd = [s:curl, '-X', 'POST', '-H', 'Content-Type: application/json', '-H', 'Accept: application/json',
|
|
\ '-H', 'Authorization: Bearer ' . g:chat_gitter_token,
|
|
\ printf('https://api.gitter.im/v1/rooms/%s/chatMessages', roomid),
|
|
\ '-d',
|
|
\ s:JSON.json_encode({'text' : a:msg})
|
|
\ ]
|
|
call s:JOB.start(cmd)
|
|
endfunction
|
|
|
|
function! chat#gitter#get_user_count(room) abort
|
|
let room = filter(deepcopy(s:channels), 'has_key(v:val, "uri") && v:val.uri ==# a:room')
|
|
if !empty(room)
|
|
return room[0].userCount . ' PEOPLE'
|
|
else
|
|
return ''
|
|
endif
|
|
|
|
endfunction
|