2017-10-23 5 views
2

사용자가 GitHub에 커밋 한 "행진"(몇 일 연속)을 반환하는 코드를 작성했습니다. 유감스럽게도 GitHub API 요청을 재귀 적으로 작성하므로 속도가 빠른 문제 (API 토큰을 사용하는 경우도 있음)가 빠르게 발생합니다. 이 정보를 검색하는 더 좋은 방법이 있습니까? 속도 제한으로 실행GitHub 속도 제한으로 인해 사용자 커밋 내역이 반환되지 않습니다.

enter image description here

내 샘플 코드 :

const express = require('express'); 
const request = require('request'); 
const moment = require('moment'); 
require('dotenv').config(); 

const app = express(); 

const port = 5000; 

app.get('/streak/:user', async function (req, res) { 
    const yesterdaysDate = moment().subtract(1, 'day').format('YYYY-MM-DD'); 
    try { 
     const streakCountTotal = await checkUserCommitForDate(req.params.user, yesterdaysDate); 
     res.send({ streakCountTotal }); 
    } catch (error) { 
     console.log(error); 
     res.sendStatus(500); 
    } 

}); 

async function checkUserCommitForDate(user, date) { 
    const authorOptions = { 
     url: `https://api.github.com/search/commits?q=author:${user}+author-date:${date}`, 
     headers: { 
      'User-Agent': 'request', 
      'Accept': 'application/vnd.github.cloak-preview', 
      'Authorization': `token ${process.env.GITHUB_SECRET_ACCESS_TOKEN}` 
     } 
    }; 
    const committerOptions = { 
     url: `https://api.github.com/search/commits?q=committer:${user}+committer-date:${date}`, 
     headers: { 
      'User-Agent': 'request', 
      'Accept': 'application/vnd.github.cloak-preview', 
      'Authorization': `token ${process.env.GITHUB_SECRET_ACCESS_TOKEN}` 
     } 
    }; 

    const githubAuthorResponse = await promisify(request)(authorOptions); 
    const githubCommitterResponse = await promisify(request)(committerOptions); 

    const githubAuthorCount = Number(JSON.parse(githubAuthorResponse.body).total_count); 
    const githubCommitterCount = Number(JSON.parse(githubCommitterResponse.body).total_count); 

    if (isNaN(githubAuthorCount) || isNaN(githubAuthorCount)) { 
     throw new Error('GitHub contribution count was not a number. Body of response was:', githubAuthorResponse.body); 
    } else if (githubAuthorCount + githubCommitterCount > 0) { 
     const previousDaysDate = moment(date).subtract(1, 'day').format('YYYY-MM-DD'); 
     let streakCounter = await checkUserCommitForDate(user, previousDaysDate); 
     streakCounter++; 
     console.log('streakCounter', streakCounter); 
     return streakCounter; 
    } else { 
     return 0; 
    } 
} 

function promisify(fn) { 
    return function (...args) { 
     return new Promise((resolve, reject) => { 
      fn(...args, (err, result) => { 
       if (err) { 
        console.log('error', err); 

        return reject(err); 
       } 
       resolve(result); 
      }); 
     }); 
    }; 
}; 

app.listen(port, function() { 
    console.log('listening on port', port); 
}); 

기본적으로 내가 무엇을 찾고 있어요 것은 사용자에 표시되는 "녹색 사각형"데이터 페이지 계정입니다

+0

요청이 완료 될 때까지 스트림 처리기에서 콜백을 연기 할 수있는 스트림으로이 코드를 다시 구성하고 싶습니다. 이렇게하면 한 번에 하나의 요청을 조절하는 매우 깔끔한 대기열을 만들 수 있으며 필요한 경우 잠시 휴식을 취하고 다시 시도 할 수있는 편리한 위치를 제공합니다. – tadman

+0

그래도 같은 수의 요청을 처리 할 수 ​​있습니다. 그렇습니까? –

+0

N 리소스를 가져오고 대량 메쏘드가 필요하지 않다면 적어도 병렬로 실행되는 것이 아니라 순차적이라면 플로우를 더 잘 제어 할 수 있습니다. – tadman

답변

2

프로필 페이지에서 사용 된 svg contribution 캘린더 데이터에서 기여 목록을 추출 할 수 있습니다.

https://github.com/users/bertrandmartel/contributions

xml을 파싱하는 것은 매우 간단하며 사용자 기여 통계는 하나의 요청을 사용하여 처리 할 수 ​​있습니다. 다음은 XML 구문 분석 cheerio를 사용하여 nodeJS 예입니다 같이 당신은 또한 기여 통계를 처리 할 수 ​​

const express = require('express'); 
const request = require('request'); 
const cheerio = require('cheerio') 

const app = express(); 
const port = 5000; 

app.get('/streak/:user', function(req, res) { 
    request('https://github.com/users/' + req.params.user + '/contributions', function(error, response, body) { 
     if (error) { 
      console.log(error); 
      res.sendStatus(500); 
      return; 
     } 
     processContrib(res, body); 
    }); 
}); 

function processContrib(res, body) { 
    var $ = cheerio.load(body); 
    var data = []; 
    $('svg').find('rect').each(function(index, element) { 
     data.push({ 
      count: parseInt($(element).attr('data-count')), 
      date: new Date($(element).attr('data-date')) 
     }) 
    }); 

    var yesterday = new Date(); 
    yesterday.setDate(yesterday.getDate() - 1); 

    data = data.sort(function(a, b) { 
     return new Date(b.date) - new Date(a.date); 
    }).filter(function(el) { 
     return el.date.getTime() <= yesterday.getTime(); 
    }); 
    var streakCount = 0; 
    for (var i = 0; i < data.length; i++) { 
     if (data[i].count == 0) { 
      break; 
     } 
     streakCount++ 
    } 
    res.status(200).json({ 
     streak: streakCount 
    }); 
} 

app.listen(port, function() { 
    console.log('listening on port', port); 
}); 

참고 here

주의해야 할 점은 공식 API를 사용하지 않을거야하지만 이벤트가 고려되는 것입니다 달력 API에 대한 기여도는 변경 될 수 있습니다. API를 사용하여 정의 된 것과 동일한 조건을 다시 정의해야합니다. here