매일매일 개발하구 매일매일 재미있게 매일매일 커밋하쟝
학부생때는 깃헙을 잠깐잠깐 쓰다가 본격적으로 사용한지는 1년 조금 넘었다. 매일매일 공부하면서 1일 1커밋 이상은 꼭 하려고 노력하고 있다. 문득 오늘의 커밋을 체크하고 알려주는 "커밋알리미"가 있으면 좋겠다고 생각을 했고 바로 실행에 옮겼다. 따로 설정을 하지 않아도 동작해야하므로 UI는 제거하고 윈도우 프로그램으로 제작하기로 했다.
C#으로 WindowService로 등록을 해서 컴퓨터가 부팅만 되있다면 자동으로 저녁 자정 전 1시간 전에 사용자의 커밋 여부를 판단하고 내 SMS로 문자를 전송해주도록 설계해 보았다.
로직은 API에서 특정 사용자의 모든 레퍼지토리를 받아 레퍼지토리의 가장 최신 커밋을 확인한다. 이후 사용자가 오늘 커밋한 내용이 존재하지 않는다면 SMS로 깃헙 커밋하라고 혼내주는(?) 문자가 간다. 다만 API 호출에 Rate Limit가 걸려있는데 초당 60번 정도로, 레퍼지토리가 많다면 성능저하가 심각하고 limit에 걸려 호출도 되지않는 문제가 존재하는데, 이는 다른 Github의 Event API를 호출하거나 accessToken을 발급받으면 limit가 풀리게 된다.
🎨API 호출 Class
1. 유저 repository 호출(Get a repository)
GET users/{user_name}/repos
JSON형태의 내 레포지토리들을 얻어 파싱해준다. 여기서 레포지토리 정보를 얻어준다. 꼭 accessToken을 발급받아 http Header에 Authcation을 추가해 주도록하자.
/// <summary>
/// 레포지토리 리스트 출력
/// </summary>
/// <param name="username"></param>
/// <returns></returns>
public dynamic GetRepoList(string username)
{
Object obj = null;
try
{
HttpWebRequest objWRequest =
(HttpWebRequest)System.Net.WebRequest.Create("https://api.github.com/users/" + username + "/repos");
objWRequest.UserAgent =
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36";
objWRequest.Headers.Add("Authorization", "Token:" + accessToken);
HttpWebResponse objWResponse = (HttpWebResponse)objWRequest.GetResponse();
Stream stream = objWResponse.GetResponseStream();
StreamReader reader = new StreamReader(stream);
string result = reader.ReadToEnd();
stream.Close();
objWResponse.Close();
obj = JsonConvert.DeserializeObject(result);
}
catch (Exception e) { }
if (obj is string)
{
return obj as string;
}
else
{
return GetDynamicObject(obj as JToken);
}
}
2. 동적 JSON 파싱 및 repository 커밋들 호출(Get commits)
GetDynamicObject는 다중 JSON 형태의 파일을 동적으로 처리해서 Object 형식의 리스트로 반환시켜주는 함수로 추가해서 사용해주었다. 이외에도 특정 레포지토리의 커밋을 도출하는 API를 받아오는 메소드도 작성해주었다. (git 참고) Commit 리스트를 바로 체크하면서 오늘 커밋이 발견될 시 바로 break 해줘 불필요한 성능 하락을 막도록 해주었다.
/// <summary>
/// dynamic JSON 받기
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
private static dynamic GetDynamicObject(JToken token)
{
if (token is JValue)
{
return (token as JValue).Value;
}
else if (token is JObject)
{
ExpandoObject expandoObject = new ExpandoObject();
(from childToken in token where childToken is JProperty select childToken as JProperty).ToList().ForEach
(
property =>
{
((IDictionary<string, object>)expandoObject).Add(property.Name, GetDynamicObject(property.Value));
}
);
return expandoObject;
}
else if (token is JArray)
{
List<ExpandoObject> list = new List<ExpandoObject>();
foreach (JToken item in token as JArray)
{
list.Add(GetDynamicObject(item));
}
return list;
}
return null;
}
다른 방법도 써보려고(위의 함수 이외) JArray, JObject를 이용한 방법으로 파싱해서 사용해보았는데 그냥 둘다 필요없고 모델객체 생성해서 모델로 파싱해서 JSON 역직렬화 시켜주는게 역시 제일 쓰기도 좋고 타입안정성도 보장된다는 생각이 들었다. 만들고 보니까 커밋을 했을때도 알림을 보내면 좋겠다는 생각이 드는데 앞으로 차차 발전시켜 나가야 댈거같다.
foreach (KeyValuePair<string, object> k in repoList[j])
{
if (k.Key.Trim().Equals("full_name"))
{
Console.WriteLine(k.Value);
string repo = k.Value.ToString();
string repoStr = GetRepoCommitStr(repo);
var jarr = JArray.Parse(repoStr);
string jo = (string)jarr.First["commit"]["author"]["date"];
//오늘날짜 커밋일시
if (today.Equals(jo.Substring(0, 10).Trim()))
{
return true;
}
}
}
📬SMS 보내기
갑자기 뜬금없이 이야기한다면, 입사해서 팀장님에게 이것저것 많이 배우고 있는데, 무엇보다 개발자로써의 신념에서 많이 배웠다. "불가능이란 단어를 모르는 개발자"라는 수식어가 따라붙는다는데 이게 너무 멋있어 보였다. 근데 안된다고 말한게 바로 이것. (무료) SMS 인증이었다. 내가 맡은 MBC 아카이브 웹에서 이번에 추가적인 개인정보 암호화 작업을 진행하면서 자연스래 회원가입/ 수정도 좀더 정교하게 만졌는데, 흔한 웹에서 있는 휴대폰 인증 기능을 너무나 하고 싶었다.
대체재로 자체 SMTP를 통한 Mail인증으로 전환했는데 그래도 한번 해보고 싶었던 일이라 커밋알람이라도 보내보려고 한다. 다행히 Twilio 에서 trial account를 발급받아 15$정도의 금액을 시험으로 써볼 수 있었고 이를 통해 구현했다.
Twilio의 계정을 생성한 뒤 사용할 수 있으며 Programmable SMS를 연동했다. VS에서는 Nuget에 Twilio 를 import 받아서 사용해주도록 한다. token , sid, 임시 전화번호 등을 발급받아 사용해주도록 하자.
using Twilio;
using Twilio.Rest.Api.V2010.Account;
class Program
{
static void Main(string[] args)
{
// Find your Account Sid and Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
string accountSid = Environment.GetEnvironmentVariable("TWILIO_ACCOUNT_SID");
string authToken = Environment.GetEnvironmentVariable("TWILIO_AUTH_TOKEN");
TwilioClient.Init(accountSid, authToken);
var message = MessageResource.Create(
body: "Join Earth's mightiest heroes. Like Kevin Bacon.",
from: new Twilio.Types.PhoneNumber("+15017122661"),
to: new Twilio.Types.PhoneNumber("+15558675310")
);
Console.WriteLine(message.Sid);
}
}
하다보니까 git token도 그렇고 twilio도 들어가는게 많이 존재하는데, 하드코딩으로 박기보다 key.txt파일을 만들어서 필요한 내용을 꺼내서 쓸 수 있도록 해주었다. 자세한 사항은 깃허브를 참조.
📆 스케쥴러(23:00~24:00) 실행
윈도우 서비스를 스케쥴러로 특정시간에 실행되도록 해도 되지만, 이번에는 1시간에 한번씩 실행되도록 설계했다.(이후 기능 추가때문에) 하루가 끝나는 잊어버릴만한 저녁 11시 넘어서 프로그램이 자동실행되서 메신저를 보내보자. 요지는 1시간마다 프로그램을 실행해 로그도 찍고 커밋검사도 하는...그런....
string _scheduleTime = "23";
public Service1()
{
InitializeComponent();
System.Timers.Timer aTimer = new System.Timers.Timer(60 * 60 * 1000);//60분마다 한번씩
aTimer.Elapsed += new System.Timers.ElapsedEventHandler(aTimer_Elapsed);
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
💻 테스트
윈도우 서비스는 디버깅이 힘들어서 윈폼으로 테스트하고 서비스에 등록해줬다. 저녁에 여지없이 매의눈으로 회초리 때리는 Gitalarmi.
🧤 마치며
만들고 나서 미리 만든게 있나 찾아보니 Slack 알람도 있던데 계속 사용한다면 SMS은 유료여서 부득이하게 메일이나 슬랙 알림으로 만족하고 써야할 것 같다. 회사에서 Slack을 사용하지 않고 나도 Notion을 개인적으로 사용해서 그다지 매력적이지 않았기도 하고... 무엇보다 SMS 서비스 연동해서 써보고 싶었다... 자세한 소스코드는 URL참조하세욤🎁
+ 요즘 개발이 재밌어서 이것저것 해보고 있는데, 현재 개발자 친구들과 개발 크루도 만들고 정말로 행복하게 보내고 있다. 차장님에게 매일 개발에 대해 묻고 토이 프로젝트도 물어보고 있는데, 비트코인 Auto Bot을 만들어 보는게 어떻겠냐고 우스갯소리로 말씀하셨다. 근데 여기에 또 혹해서 진행 중에 있다. 유의미한 결과 나올때 업로드 하도록 해야겠다. ㅇㅅㅇ
'프로젝트 직딩일기' 카테고리의 다른 글
[WEB웹자동화] Auto_portal 개발기 (0) | 2021.04.05 |
---|---|
서버로 부터 받은 이미지 리소스의 로딩 시 속도 저하 개선 경험 (0) | 2021.03.21 |